Files
hospital-rescue-app-v2/uni_modules/tmx-ui/components/x-text/x-text.uvue
T
2026-09-24 16:25:22 +08:00

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>