先看效果
主要结构
我用的mpvue,如用原生标签直接转换成原生即可
<div id="labelBox">
<div class="label userLabel" v-for="(label,inx) in labelList" :key="inx">{{label}}</div>
<div class="more" v-show="showLabel===1" id="moreLabel" @click="openMore">
<div>全部{{allLabel.length}}个</div>
<img class="icon ml5" src="/static/img/i_label_down.png" />
</div>
<div class="more" v-show="showLabel===2" @click="closeMore">
<div>收起</div>
<img class="icon ml5" src="/static/img/i_label_up.png" />
</div>
</div>
export default {
data() {
return {
labelList: [],// 视图显示的标签集合
allLabel: [],// 所有的标签集合
firstLabel: [],// 默认显示的标签集合
showLabel: 1,// 0 两个按钮都不显示,1 显示展开,2 显示收起
}
},...
}
思路
利用小程序api NodesRef.boundingClientRect 获取节点的位置与大小信息,主要用到 width
,left
,246);'>right
- 循环所有标签(
.userLabel
),看是否有多行,通过所有节点的left
去判断,如果left
相同的有多个,就证明有多行 - 获取标签父级(
#labelBox
)的宽度width
- 获取到按钮(
#moreLabel
)的宽度 - 过滤第一行节点的
right
,如果与按钮的width
相加小于等于父级盒子的width
就保留
具体的代码
wxp为微信接口Promise化,会在之后列出用到的
export default {
data() {
return {
labelList: [],methods: {
async loadPageData(){
// 请求后台数据
const res = ...
// 设置
this.allLabel = res.labes; // 记录所有的标签
this.labelList = this.allLabel; // 先插入所有表情
// 设置状态
if(this.allLabel.length>0){
await wxp.timeout(300); // 插入视图之后不会马上获取到节点信息,延迟获取
this.setLabelStauts();
}
},// 设置标签状态
async setLabelStauts(){
const boxDom = await wxp.getElementById('#labelBox');
const labelDoms = await wxp.getElementsByClassName('.userLabel');
const btnDom = await wxp.getElementById('#moreLabel');
const left = labelDoms[0].left;
// 分行转为二维数组
let lineArr = [];
let lineIndex = -1;
labelDoms.forEach(v => {
if(v.left==left){
lineIndex++;
lineArr[lineIndex] = [];
}
lineArr[lineIndex].push(v);
})
// 超过一行
if(lineArr.length>1){
// 默认显示加载更多按钮
this.showLabel = 1;
const firstTr = lineArr[0].filter(v => (v.right+btnDom.width+(left/15*15)) <= boxDom.width);
this.firstLabel = this.allLabel.slice(0,firstTr.length);
this.labelList = this.firstLabel;
}else{
this.showLabel = 0;
}
},// 展开
openMore(){
this.showLabel = 2;
this.labelList = this.allLabel;
},// 收起
closeMore(){
this.showLabel = 1;
this.labelList = this.firstLabel;
}
}
}
wxp.js相关代码
/**
* 延时
* @param {*} delay
*/
export const timeout = delay => new Promise(resolve => setTimeout(resolve,delay));
/**
* 根据ID获取dom的盒模型信息
* @param {*} id
*/
export const getElementById = (id='') => {
return new Promise((resolve,reject) => {
if ((typeof id).toLowerCase() !=='string'){
const err = {
errMsg: '请输入字符串,例如 #box'
}
reject(error(err.errMsg,err));
} else if (id.indexOf('#') < 0) {
const err = {
errMsg: '请输入ID,例如 #box'
}
reject(error(err.errMsg,err));
}else{
var query = wx.createSelectorQuery()
query.select(id).boundingClientRect();
query.selectViewport().scrollOffset();
query.exec(rect => {
if (rect[0]){
let info = rect[0];
info.position = {
left: rect[1].scrollLeft + info.left,top: rect[1].scrollTop + info.top
};
resolve(info);
}else{
const err = {
errMsg: '没有获取到信息'
}
reject(error(err.errMsg,err));
}
})
}
})
}
/**
* 根据类名获取dom信息
* @param {*} className
*/
export const getElementsByClassName = (className = '') => {
return new Promise((resolve,reject) => {
if ((typeof className).toLowerCase() !== 'string') {
const err = {
errMsg: '请输入字符串,例如 .box'
}
reject(error(err.errMsg,err));
} else if (className.indexOf('.') < 0) {
const err = {
errMsg: '请输入类名,例如 .box'
}
reject(error(err.errMsg,err));
} else {
wx.createSelectorQuery().selectAll(className).boundingClientRect(rects => {
resolve(rects);
}).exec();
}
})
}
作者:不二很纯洁
链接:https://www.jianshu.com/p/87f3c14038a6
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。