小程序标签展开收起功能实现

先看效果


主要结构

我用的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

  1. 循环所有标签(.userLabel),看是否有多行,通过所有节点的 left 去判断,如果 left 相同的有多个,就证明有多行
  2. 获取标签父级(#labelBox)的宽度 width
  3. 获取到按钮(#moreLabel)的宽度
  4. 过滤第一行节点的 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(); } }) }


作者:不二很纯洁
链接:jianshu.com/p/87f3c1403

相关文章

概述 消息能力是小程序能力中的重要组成,我们为开发者提供了...
判断H5页面环境在微信中还是小程序中 用小程序提供的wx.mini...
wx.reLaunch和wx.navigateTo,wx.navigateTo的区别 2019-03-...
微信小程序如何从数组里取值_微信小程序 传值取值的几种方法...
H5项目接入微信授权登录,通过 UA 区分微信还是普通浏览器:...
微信小程序获取data-xx=&quot;&quot;属性的值,自定...