Files
pj_h5_cloud/src/uni_modules/tm-ui/components/tm-text/tm-text.vue
T
2024-11-11 14:42:47 +08:00

278 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view @click="OnClick" :style="[_style]" class="xTextLines">
<!--
@slot 默认文本插槽,如果使用插槽,那么相关特性功能将会失效。
因此不建议使用插槽,还不如自己用text标签。
-->
<slot>
<text v-if="_label.length == 0" :user-select="selectable" :selectable="selectable">{{ _attrs.label }}</text>
</slot>
<text @click="itemClick(item.text)" :selectable="selectable" :style="[
{
color: item.color,
lineHeight: lineHeight,
fontSize: _fontSize,
},
item.isHeightLight ? heightLightStyle : '',
]" v-for="(item, index) in _label" :key="index">
{{ item.text }}
</text>
</view>
</template>
<script setup lang="ts">
import { computed, ref, useSlots } from "vue";
import { arrayNumberValid, arrayNumberValidByStyleMP, covetUniNumber, linearValid, getUnit } from "../../libs/tool";
import { useTmConfig } from "../../libs/config";
import { getDefaultColor, setTextColorLightByDark, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors";
/**
* @displayName 文本
* @exportName tm-text
* @category 常用组件
* @description 允许正则高亮或者,词高亮.
* @constant 平台兼容
* | H5 | uniAPP | 小程序 | version |
| --- | --- | --- | --- |
| ☑️| ☑️ | ☑️ | ☑️ | ☑️ | 1.0.0 |
*/
defineOptions({ name: 'TmText' });
const { config } = useTmConfig()
const slots = useSlots()
type ITEMINFO = {
text: string,
color: string,
isHeightLight: boolean
}
const emits = defineEmits([
/**
*文本点击
* @property {String} word 点击的文本内容
* */
'click',
/**
*正则的文本被点击
* @property {String} word 点击的文本内容
* */
'itemClick'
])
// 使用defineProps定义组件的props
const attrs = defineProps({
/**
* 文本内容
* 这个prop用于接收显示在组件中的文本或数字
*/
label: {
type: [String, Number],
default: ''
},
/**
* 需要特别高亮的词
*/
heightLight: {
type: [Array<string>],
default: (): string[] => [] as string[]
},
/**
* 高亮正则
* 用于定义文本中哪些部分应该被高亮显示的正则表达式数组
*/
heightLightReg: {
type: [Array<string>],
default: () => []
},
/**
* 高亮文本的自定义样式
*/
heightLightStyle: {
type: String,
default: ""
},
/**
* 行数
* 控制文本显示时应该占用的行数(如果组件支持此功能)
*/
lines: {
type: [Number, String],
default: 0
},
/**
* 是否可选
* 指示文本是否可以被用户选择(如通过长按选择)
*/
selectable: {
type: Boolean,
default: false
},
/**
* 文本颜色
* 定义文本的主要颜色
*/
color: {
type: String,
default: "#333"
},
/**
* 暗色模式颜色
* 在暗色模式下文本的颜色(如果组件支持暗色模式)
*/
darkColor: {
type: String,
default: ""
},
/**
* 高亮颜色
* 文本中应该被高亮显示的部分的颜色
*/
heightLightColor: {
type: String,
default: "primary"
},
/**
* 行高
* 文本的行高设置
*/
lineHeight: {
type: [String, Number],
default: "1.5"
},
/**
* 字体大小
* 文本的字体大小设置
*/
fontSize: {
type: [String, Number],
default: ""
},
})
const _attrs = computed(() => attrs)
/**
* 点击事件处理函数
* @returns 无返回值
*/
const OnClick = () => {
emits('click', attrs.label)
}
/**
* 正则的文本被点击
* @param text 被点击的文本内容
*/
const itemClick = (text: string) => {
emits('itemClick', text)
}
const _color = computed((): string => {
let color = attrs.color;
if (config.mode == 'dark') {
if (attrs.darkColor != "") {
color = attrs.darkColor!
return getDefaultColor(color)
}
return setTextColorLightByDark(color)
}
return getDefaultColor(attrs.color)
})
const _label = computed((): ITEMINFO[] => {
let slotsdefault = slots.default;
if (typeof slotsdefault == 'function') {
if (slotsdefault().length > 0) return [] as ITEMINFO[];
} else if (typeof slotsdefault == 'boolean') {
if (slotsdefault) return [] as ITEMINFO[];
}
let keywords = attrs.heightLight
let albel = typeof attrs.label == 'number' ? attrs.label.toString() : attrs.label;
if ((keywords.length == 0 && attrs.heightLightReg.length == 0) || albel.length == 0) {
return [{ text: albel, color: _color.value, isHeightLight: false } as ITEMINFO]
}
let regexxAr = [] as string[];
attrs.heightLightReg.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 regex = new RegExp(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: _heightLightColor.value,
isHeightLight: true
} as ITEMINFO)
} else {
ar.push({
text: el,
color: _color.value,
isHeightLight: false
} as ITEMINFO)
}
}
})
return ar;
})
const _heightLightColor = computed((): string => {
return getDefaultColor(attrs.heightLightColor)
})
const _fontSize = computed((): string => {
let fontSize = attrs.fontSize || config.fontSizeBase
fontSize = covetUniNumber(fontSize, config.unit);
if (config.fontSizeScale == 1) return fontSize;
let sizeNumber = parseInt(fontSize)
if (isNaN(sizeNumber)) {
sizeNumber = 28
}
return (sizeNumber * config.fontSizeScale).toString() + getUnit(fontSize)
})
const _style = computed((): { [key: string]: any } => {
let obj: { [key: string]: any } = {}
obj["-webkit-line-clamp"] = attrs.lines.toString()
obj["lineHeight"] = attrs.lineHeight
obj["fontSize"] = _fontSize.value
obj["color"] = _color.value
return obj
})
</script>
<script lang="ts">
export default {
options: {
styleIsolation: "apply-shared",
virtualHost: true,
addGlobalClass: true,
multipleSlots: true,
},
};
</script>
<style lang="scss" scoped></style>