龙空技术网

自定义一个各端通用的文本省略组件(ellipsis)

没事来搬砖 109

前言:

此刻我们对“前端自定义控件有哪些”大概比较关切,姐妹们都需要了解一些“前端自定义控件有哪些”的相关知识。那么小编同时在网上汇集了一些对于“前端自定义控件有哪些””的相关内容,希望姐妹们能喜欢,姐妹们一起来了解一下吧!

组件效果图:

现有方案壁垒:

如果你做的是前端开发,你可能会经常遇到长度不够或高度不够时进行文本省略,这个也很简单,如下css代码就可以实现1行或n行的自动省略:

/*一行多余省略:*/.t-text-oneline {   overflow: hidden;   text-overflow: ellipsis;   white-space: nowrap;}/*n行多余省略:*/.t-text-nline {  display: -webkit-box;  word-break: break-all;  text-overflow: ellipsis;  overflow: hidden;  -webkit-box-orient: vertical;  -webkit-line-clamp: 2; /*只需改变这里值为n即可*/}

上面针对多余文字通过省略隐藏达到样式不变的效果,但是用户无法看到内容的全部文字,或者说需要一些处理才可以让用户看到,例如点击跳转详情页展示或者tip提示组件等,总之用起来缺乏“美感”。

场景描述:

文本要能全部展示,而且通过用户主动触发展示与不展示。因为用户一般只会对自己感兴趣的文章才会看全文,这样就需要一个既能满足上面简单需求,又能满足全文查看,且方便用户操作的体验友好的组件,这也是本组件编写的目的。

兼容性:

需要全端兼容所以使用uniapp框架,满足easycom组件规范,用户导入hbuilder后直接通过标签引用使用,非常方便。

实现原理:

根据原view设置的默认显示行数、文字大小等信息,虚拟一个相同的view容器,该view中把文字全部展示出来,通过以上信息计算出每行大概有多少个字符(汉字算两个,其他算1个),根据字符数对全文内容进行截取,再通过原view高度和虚拟view高度比较如果相等则停止计算,得到最终需要显示的字符串进行渲染。

直接上正文,自定义组件全过程:

1.hbuilder新建一个项目,选择默认第一个hello uniapp模板即可;

2.项目根目录下新建components目录;

3.在components目录下新建组件目录,例如这里命名为kevy-ellipsis的组件目录;

4.在kevy-ellipsis目录下新建kevy-ellipsis.vue文件,其内容为组件代码

kevy-ellipsis.vue代码如下:

<template>	<view class="t-wrap">		<!-- 虚拟view用于计算,计算完成则消失 -->		<view class="t-txt-hide" :id="hid" v-if="!isCompute" :style="[computeStyle(0)]">			{{testContent?testContent:content}}{{showSymbol?'...':''}}<text v-if="expandText && collapseText"				class="t-button">				{{expandText}}			</text>		</view>		<!-- 真实显示的内容 -->		<view class="t-ellipsis" :id="id" :style="[!isCompute?computeStyle(1):computeStyle(2)]" @click="contentClick">			{{(!isCompute || expand)?content:(actualContent+(showSymbol?'...':''))}}<text				v-if="expandText && collapseText && showSymbol" class="t-button" @click.stop="changeCollapse"				:style="{'color':actionFontColor,'float':'right'}">{{!expand?expandText:collapseText}}</text>		</view>		<!-- 这里加入了自定义的动态骨架屏友好反馈 -->		<view v-if="!isCompute && rows>0" class="t-skeleton">			<view class="skeletons" v-for="(item,index) in rows">				<view class="empty"></view>			</view>		</view>	</view></template><script>	import {		init,		computeStyle,		compute	} from './kevy-ellipsis.min.js'	export default {		name: "kevy-ellipsis",		props: {			/**			 * 文本内容,默认''			 */			content: {				type: String,				default: ''			},			/**			 * 字体大小,单位rpx,默认28			 */			fontSize: {				type: Number,				default: '28'			},			/**			 * 字体颜色,默认#666666			 */			fontColor: {				color: String,				default: '#666666'			},			/**			 * 收起操作的文案,默认''			 */			collapseText: {				type: String,				default: ''			},			/**			 * 展开操作的文案,默认''			 */			expandText: {				type: String,				default: ''			},			/**			 * 收起、展开操作文字颜色,默认'#007aff'			 */			actionFontColor: {				color: String,				default: '#007aff'			},			/**			 * 展示行数,默认1			 */			rows: {				type: Number,				default: 1			},		},		data() {			return {				//是否展开				expand: false,				//是否已计算				isCompute: false,				//内容高度				h: undefined,				//内容宽度				w: undefined,				//实际显示内容				actualContent: '',				//高度探测内容				testContent: undefined,				//是否显示省略号				showSymbol: false,				//hid和id,唯一标识符				hid: 'hid' + Math.random().toString(36).substr(2),				id: 'id' + Math.random().toString(36).substr(2),			};		},		created() {			if (this.content?.length > 0) {				// #ifdef H5				this.$nextTick(() => {					init(this, () => {						compute(this);					})				})				// #endif					// #ifdef MP-ALIPAY				init(this, () => {					compute(this, true);				}, true)				// #endif				// #ifndef MP-ALIPAY || H5				init(this, () => {					compute(this);				})				// #endif			}		},		computed: {			computeStyle		},		methods: {			//收起展开状态切换			changeCollapse() {				this.expand = !this.expand;			},			//文本点击事件			contentClick() {				this.$emit('contentClick');			}		}	}</script><style lang="scss" scoped>	.t-wrap {		width: 100%;		box-sizing: border-box;		position: relative;	}	.t-txt-hide {		word-break: break-word;		position: absolute;		top: 999999px;		left: 999999px;		z-index: -1000;		top: 0rpx;		width: 100%;		margin: 0rpx;		text-align: justify;	}	.t-ellipsis {		text-align: justify;		box-sizing: border-box;		width: 100%;		word-break: break-word;		position: relative;		left: 99999px;	}	.t-skeleton{		width: 100%;		height: 100%;		box-sizing: border-box;		position: absolute;		top: 0rpx;		left: 0rpx;	}	.skeletons:first-child{		margin-top: 0rpx !important;	}	.skeletons {		position: relative;		display: block;		overflow: hidden;		width: 100%;		height: 32rpx;		margin-top: 12rpx;		background-color: rgba(0, 0, 0, 0.06);		box-sizing: border-box;	}	.skeletons .empty {		display: block;		position: absolute;		width: 100%;		height: 100%;		-webkit-transform: translateX(-100%);		transform: translateX(-100%);		background: linear-gradient(90deg, transparent, rgba(216, 216, 216, 0.753), transparent);		-webkit-animation: loading .8s infinite;		animation: loading .8s infinite;	}	@keyframes loading {		100% {			-webkit-transform: translateX(100%);			transform: translateX(100%);		}	}</style>

5.在kevy-ellipsis同目录下新建kevy-ellipsis.min.js,即上面代码中引入的工具类,为了防止他人冒用这里进行了代码混淆(如需该工具类源码关注并评论回复留下邮箱),代码如下:

"use strict";function _typeof(e){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function ownKeys(t,e){var o,n=Object.keys(t);return Object.getOwnPropertySymbols&&(o=Object.getOwnPropertySymbols(t),e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,o)),n}function _objectSpread(t){for(var e=1;e<arguments.length;e++){var o=null!=arguments[e]?arguments[e]:{};e%2?ownKeys(Object(o),!0).forEach(function(e){_defineProperty(t,e,o[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(o)):ownKeys(Object(o)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(o,e))})}return t}function _defineProperty(e,t,o){return(t=_toPropertyKey(t))in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function _toPropertyKey(e){e=_toPrimitive(e,"string");return"symbol"===_typeof(e)?e:String(e)}function _toPrimitive(e,t){if("object"!==_typeof(e)||null===e)return e;var o=e[Symbol.toPrimitive];if(void 0===o)return("string"===t?String:Number)(e);o=o.call(e,t||"default");if("object"!==_typeof(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}var init=function(t,o,e){(e?uni.createSelectorQuery().in().select("#"+t.id).boundingClientRect(function(e){t.h=Number(e.height.toFixed(1)),o&&o()}):uni.createSelectorQuery().in(t).select("#"+t.id).boundingClientRect(function(e){t.h=Number(e.height.toFixed(1)),o&&o()})).exec()},computeStyle=function(n){return function(e){var t=0<n.rows?n.rows:1,o={};return 1==e?o={"-webkit-line-clamp":t,display:"-webkit-box","text-overflow":"ellipsis",overflow:"hidden","-webkit-box-orient":"vertical"}:2==e&&(o=_objectSpread({position:"relative",left:"0rpx"},o)),_objectSpread({"font-size":n.fontSize+"rpx",color:n.fontColor},o)}},computeContent=function t(e,o,n,r){var i=e,c=i.h,u=i.testContent,l=i.content;l.length;i.testContent=u?n?l.substring(0,n):u:l,i.$nextTick(function(){getH(e,o,function(e){c<e?(i.showSymbol=!0,-1===r||void 0===r?t(i,o,Math.floor(i.testContent.length/2),-1):1===r&&(i.actualContent=l.substring(0,n-1),i.isCompute=!0)):i.showSymbol?-1!==r&&1!==r||t(i,o,n+1,1):(i.actualContent=l,i.isCompute=!0)})})},getH=function(e,t,o){(t?uni.createSelectorQuery().in().select("#"+e.hid).fields({size:!0},function(e){o(Number(e.height.toFixed(1)))}):uni.createSelectorQuery().in(e).select("#"+e.hid).fields({size:!0},function(e){o(Number(e.height.toFixed(1)))})).exec()};module.exports={init:init,computeStyle:computeStyle,computeContent:computeContent};

组件使用

<template>	<view class="content">		<!-- 这里模拟通过请求js动态赋值 -->		<kevy-ellipsis v-if="content && content.length>0" :content="content" font-color="#666666" :font-size="32" :rows="3" @contentClick="myclick" collapseText="收起" expandText="展开" actionFontColor="#007aff"></kevy-ellipsis>		<view class="mg"></view>		<!-- 这里模拟直接复制给组件(例如循环) -->		<kevy-ellipsis content="这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。" font-color="#666666" :font-size="32" :rows="3" @contentClick="myclick" collapseText="收起" expandText="展开" actionFontColor="#007aff"></kevy-ellipsis>	</view></template><script>	import kevyEllipsis from '@/components/kevy-ellipsis/kevy-ellipsis'	export default {		components: {			kevyEllipsis		},		data() {			return {				content:""			}		},		onLoad() {			//这里模拟请求到数据赋值给组件			this.content="这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。这是一个uniapp通用的超长文本处理组件,简单的设置达到自动适配超长文本溢出兼容效果。";		},		methods: {			//点击文本			myclick(){				console.log("哈哈,你点击文本了。。。");			}		}	}</script><style scoped>	.content {		box-sizing: border-box;		width: 100%;		padding: 24rpx;	}	.mg{		padding: 50rpx;	}</style>
方法和属性

名称

类型

描述

content

String

文本内容,默认’’

rows

Number

展示行数,默认1

fontSize

Number

文本字体大小,单位rpx,默认28

fontColor

String

文本字体颜色,默认#666666

collapseText

String

收起操作的文案,默认’’

expandText

String

展开操作的文案,默认’’

actionFontColor

String

收起、展开操作文字颜色,默认’#007aff’

contentClick

Func

文本点击事件函数

如果想用现成的,在插件详情页通过hbuilder直接导入即可,插件市场插件详情页地址为:

如果本文对您有帮助,还请帮忙点个赞或留下宝贵意见哦,总之谢谢您啦。

标签: #前端自定义控件有哪些