308 lines
8.1 KiB
Plaintext
308 lines
8.1 KiB
Plaintext
<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> |