1
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue"
|
||||
import { getDefaultColor, getDefaultColorObj, getTextColorObj, getThinColorObj, setTextColorLightByDark } from "../../core/util/xCoreColorUtil.uts"
|
||||
import { toFillMarginAr, checkIsCssUnit, getUnit } from "../../core/util/xCoreUtil.uts"
|
||||
import { xConfig } from "../../config/xConfig.uts"
|
||||
|
||||
type ITEMINFO = {
|
||||
text : string,
|
||||
color : string,
|
||||
isHeightLight : boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @name 文本 xText
|
||||
* @description 支持多文本高亮显示,目前uniapp x 4.0.1+正则。
|
||||
* 可允许拓展:比如根据正则高亮电话号码,邮箱等,点击后打电话,发邮件。使用时一定要注意:尽量标签内容写文本,不要用label属性,label属性是用来高亮和正则的
|
||||
* @page /pages/index/text
|
||||
* @category 常用组件
|
||||
* @constant 平台兼容
|
||||
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
||||
*/
|
||||
defineOptions({name:"xText"})
|
||||
|
||||
export type xTextPropsType = {
|
||||
/**
|
||||
* 自定文件标签的样式
|
||||
*/
|
||||
_style: string,
|
||||
/**
|
||||
* 自定文件标签的类,仅对标签插槽内的有效,如果使用label属性会变成richtext渲染,因为类将失效.
|
||||
*/
|
||||
_class: string,
|
||||
/**
|
||||
* 源文本,显示 的文本。
|
||||
*/
|
||||
label: string,
|
||||
/**
|
||||
* 需要特别高亮的词
|
||||
*/
|
||||
highlight: string[],
|
||||
/**
|
||||
* 高亮的正则,
|
||||
* 请尽量不要和highlight字段结果集重叠,
|
||||
* 也不要提供的正则数组出现重叠混乱。
|
||||
* 默认是正则电话,邮箱
|
||||
*/
|
||||
highlightReg: string[],
|
||||
/**
|
||||
* 高亮文本的自定义样式
|
||||
*/
|
||||
highlightStyle: string,
|
||||
/**
|
||||
* 最多显示几行,默认0不限制。
|
||||
* 超过了此行会出现省略号。
|
||||
*/
|
||||
lines: number,
|
||||
/**
|
||||
* 是否允许复制。
|
||||
*/
|
||||
selectable: boolean,
|
||||
/**
|
||||
* 文本颜色
|
||||
*/
|
||||
color: string,
|
||||
/**
|
||||
* 暗黑时的文本颜色,如果你不提供,将自动反转。
|
||||
* 自动反转是根据亮度反转,色相不变。
|
||||
*/
|
||||
darkColor: string,
|
||||
/**
|
||||
* 高亮颜色
|
||||
*/
|
||||
highlightColor: string,
|
||||
/**
|
||||
* 行高
|
||||
*/
|
||||
lineHeight: string,
|
||||
/**
|
||||
* 文字大小。
|
||||
*/
|
||||
fontSize: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<xTextPropsType>(), {
|
||||
_style: "",
|
||||
_class: "",
|
||||
label: "",
|
||||
highlight: () : string[] => [] as string[],
|
||||
highlightReg: () : string[] => [] as string[],
|
||||
highlightStyle: "",
|
||||
lines: 0,
|
||||
selectable: false,
|
||||
color: "",
|
||||
darkColor: "",
|
||||
highlightColor: "primary",
|
||||
lineHeight: "1.7",
|
||||
fontSize: ""
|
||||
})
|
||||
|
||||
const emits = defineEmits([
|
||||
/**
|
||||
* 点击时触发
|
||||
*/
|
||||
'click',
|
||||
/**
|
||||
* 正则的项目被点击
|
||||
* @description 微信及web有效,app无效
|
||||
* 这个功能取决于uniapp x官方的支持。
|
||||
* @param {string} str - 被点击的文本内容
|
||||
*/
|
||||
'item-click'
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const ___class = computed((): string => props._class)
|
||||
const ___style = computed((): string => props._style)
|
||||
|
||||
const _fontSize = computed((): string => {
|
||||
let basefontsize = props.fontSize == '' ? xConfig.fontSize : props.fontSize;
|
||||
let fontSize = checkIsCssUnit(basefontsize, xConfig.unit);
|
||||
if (xConfig.fontScale == 1) return fontSize;
|
||||
let sizeNumber = parseInt(fontSize)
|
||||
if (isNaN(sizeNumber)) {
|
||||
sizeNumber = 14
|
||||
}
|
||||
return (sizeNumber * xConfig.fontScale).toString() + getUnit(fontSize)
|
||||
})
|
||||
|
||||
const _color = computed((): string => {
|
||||
let color = props.color==''?xConfig.fontColor:props.color;
|
||||
if (xConfig.dark == 'dark') {
|
||||
if (props.darkColor != "") {
|
||||
color = props.darkColor
|
||||
return getDefaultColor(color)
|
||||
}
|
||||
color = xConfig.fontDarkColor==''?setTextColorLightByDark(props.color):xConfig.fontDarkColor
|
||||
}
|
||||
return getDefaultColor(color)
|
||||
})
|
||||
|
||||
const _highlightColor = computed((): string => {
|
||||
return getDefaultColor(props.highlightColor)
|
||||
})
|
||||
|
||||
const _label = computed((): string => {
|
||||
return props.label
|
||||
})
|
||||
|
||||
const _texts = computed((): ITEMINFO[] => {
|
||||
if(props.label=='') return [] as ITEMINFO[]
|
||||
let keywords = props.highlight
|
||||
let albel = props.label;
|
||||
|
||||
if ((keywords.length == 0 && props.highlightReg.length == 0) || albel.length == 0) {
|
||||
return [{ text: albel, color: _color.value, isHeightLight: false } as ITEMINFO]
|
||||
}
|
||||
|
||||
let regexxAr = [] as string[];
|
||||
|
||||
props.highlightReg.forEach(function (reg : string) {
|
||||
let regex = new RegExp(reg, 'gi');
|
||||
|
||||
let rulst = regex.exec(albel)
|
||||
while (rulst != null && Array.isArray(rulst)) {
|
||||
if (Array.isArray(rulst)) {
|
||||
let str = rulst[0]! as string;
|
||||
if (!regexxAr.includes(str)) {
|
||||
regexxAr.push(str)
|
||||
}
|
||||
|
||||
}
|
||||
rulst = regex.exec(albel)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
keywords = keywords.concat(regexxAr)
|
||||
|
||||
// 遍历关键词数组
|
||||
keywords.forEach(function (keyword : string) {
|
||||
// 创建一个正则表达式,使用'i'标志表示不区分大小写
|
||||
let reg:RegExp = new RegExp('[\\*]','gi')
|
||||
let isFuhao = reg.test(keyword)
|
||||
let regex = new RegExp(isFuhao?('\\'+keyword):keyword, 'gi');
|
||||
// 使用replace方法将匹配到的关键词用带有高亮样式的span标签包裹起来
|
||||
albel = albel.replace(regex, `~-<span>${keyword}</span>~-`);
|
||||
});
|
||||
|
||||
let ps = albel.split('~-')
|
||||
let ar = [] as ITEMINFO[]
|
||||
ps.forEach((el : string) => {
|
||||
if (el.length > 0) {
|
||||
let start = el.indexOf('<span>')
|
||||
if (start > -1) {
|
||||
let end = el.lastIndexOf('</span>')
|
||||
ar.push({
|
||||
text: el.substring(start + 6, end),
|
||||
color: _highlightColor.value,
|
||||
isHeightLight: true
|
||||
} as ITEMINFO)
|
||||
} else {
|
||||
ar.push({
|
||||
text: el,
|
||||
color: _color.value,
|
||||
isHeightLight: false
|
||||
} as ITEMINFO)
|
||||
}
|
||||
}
|
||||
})
|
||||
return ar;
|
||||
})
|
||||
|
||||
const _styleMap = computed((): Map<string, any> => {
|
||||
let styleMap = new Map<string, any>();
|
||||
if(props.lines>0){
|
||||
// #ifdef APP
|
||||
styleMap.set("lines", props.lines)
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
styleMap.set("-webkit-line-clamp", props.lines)
|
||||
// #endif
|
||||
}
|
||||
|
||||
styleMap.set("line-height", props.lineHeight)
|
||||
styleMap.set("font-size", _fontSize.value)
|
||||
styleMap.set("color", _color.value)
|
||||
return styleMap
|
||||
})
|
||||
|
||||
// 方法
|
||||
function allClick() {
|
||||
/**
|
||||
* 整个组件被点击
|
||||
*/
|
||||
emits('click')
|
||||
}
|
||||
|
||||
function itemClick(str : string) {
|
||||
// let str = event.detail.href;
|
||||
/**
|
||||
* 文本被点击。比如高亮的文本被点击。
|
||||
* @param str {string} 当前点击的文本。
|
||||
*/
|
||||
emits('item-click', str)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<text @click="allClick" :style="[_styleMap,___style]" :class="___class" class="xTextLines" :selectable="selectable"
|
||||
>
|
||||
<!--
|
||||
@slot 默认文本插槽,如果使用插槽,那么相关特性功能将会失效。
|
||||
如果没有特殊需求,建议使用插槽,文本写在标签内.如果需求正则则用label属性控制.
|
||||
-->
|
||||
<slot>
|
||||
<text v-if="_label==''" @click="allClick" :style="[_styleMap,___style]" :class="___class" class="xTextLines"
|
||||
:selectable="selectable" >
|
||||
{{_label}}
|
||||
</text>
|
||||
</slot>
|
||||
<text @click="itemClick(item.text)" :class="[___class]" :selectable="selectable" :style="[{
|
||||
color:item.color,
|
||||
lineHeight:lineHeight,
|
||||
fontSize:_fontSize,
|
||||
},item.isHeightLight?highlightStyle:{},___style]" v-for="(item,index) in _texts" :key="index" >
|
||||
{{item.text}}
|
||||
</text>
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view @click="allClick" :style="[_styleMap,___style]" :class="___class" class="xTextLines" >
|
||||
<slot>
|
||||
<text v-if="_label==''" :style="[_styleMap,___style]" :class="___class" class="xTextLines"
|
||||
:selectable="selectable" >
|
||||
{{_label}}
|
||||
</text>
|
||||
</slot>
|
||||
<text @click.stop="itemClick(item.text)" :class="[___class]" :selectable="selectable" :style="[{
|
||||
color:item.color,
|
||||
lineHeight:lineHeight,
|
||||
fontSize:_fontSize,
|
||||
},item.isHeightLight?highlightStyle:{},___style]" v-for="(item,index) in _texts" :key="index" >
|
||||
{{item.text}}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<style scoped>
|
||||
.xTextRegx {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.xTextLines {
|
||||
text-overflow: ellipsis;
|
||||
/* #ifndef APP */
|
||||
text-wrap: wrap;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
/* #endif */
|
||||
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user