微信小程序开发——wx:for循环渲染元素如何修改点击样式

来源:互联网 发布:deepskystacker mac 编辑:程序博客网 时间:2024/06/05 16:28

我们在做微信小程序的时候,往往需要做导航栏,效果是:点击导航栏的子元素,显示对应的Tab页,并且要修改点击的子元素样式用来提示用户当前位置。效果是这样:


底部导航不用说,直接在app.json中定义跳转地址和选中样式即可。关键是自定义导航,需要我们自己定义。

相信看过小程序API的人都知道导航栏怎么写:在wxml中列出每个导航栏,指定每个导航栏的url和点击样式就可以了。不清楚的童鞋可以查看API:微信小程序导航栏API

就像这样:

<!-- sample.wxml --><view class="btn-area">  <navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>  <navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator>  <navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator></view>

但是这种做法只能算入门级,因为前台wxml视图文件没有和后台数据分离,导致导航栏不是动态加载(根据请求的JSON数据渲染导航栏)。这样的话,如果我们要修改导航栏,就只能修改wxml文件,不易维护。

好的做法是动态请求JSON数据,循环渲染出整个导航栏。如果需要修改导航栏,通过后台修改数据库中导航栏的数据即可,后台返回JSON数据给展示页面,展示页面调用this.setData({})方法即可绘制出新的导航栏。

JSON数据存储了导航栏各个子元素信息,其中goodsName对应上图的名称,goodsId用于标识每个元素,goodsClass用来定义图片路径,如下:

  [{    "goodsName":"油烟机",    "goodsId":"1",    "goodsClass":"yanji"  },{    "goodsName":"热水器",    "goodsId":"2",    "goodsClass":"reshuiqi"  },{    "goodsName":"灶具",    "goodsId":"3",    "goodsClass":"zao"  },{    "goodsName":"浴室柜",    "goodsId":"4",    "goodsClass":"yushigui"  },{    "goodsName":"花洒",    "goodsId":"5",    "goodsClass":"huasa"  },{    "goodsName":"马桶",    "goodsId":"6",    "goodsClass":"matong"  }]


wxml页面这样写即可循环渲染每一个导航栏,其中用到了wx:for="{{navList}}"来遍历页面data数据中的navList值,而这个navList就是我们请求的JSON。wx:for内层结构中的{{item.goodsId}}对应每个导航栏子元素的goodsId属性值,其他如{{item.goodsName}}以此类推。到这儿,你的页面应该能够渲染出整个导航栏了,但是还没有点击修改样式的功能。

<view class="container clearfloat">  <view class="leftNav">    <block wx:for="{{navList}}" wx:key="goodsId">      <view style="color:{{item.goodsId==currentItemId?'#e98f36':'#000'}}" data-num="{{item.goodsId}}" class="goodsTitle" bindtap="clickTap">        <image src="/images/{{item.goodsClass}}{{item.goodsId==currentItemId?2:1}}.png"></image>        <!--<image src="{{item.goodsImg}}"></image>-->        <span>{{item.goodsName}}</span>       </view>    </block>  </view></view>

如果这些你读起来困惑,别急,之前的内容了解一下就好,再不行去看看小程序API中的wx:for你就能够做到。接下来给每个循环的子元素增加点击样式才是本文重点,看完下面的操作以后,相信你能够豁然开朗。

我们可以给每个子元素添加点击事件:上面代码中的bindtap="clickTap"就是给每个元素添加点击事件,这个点击事件处理函数在js文件中定义。下面我直接贴出这个页面的完整js文件:

Page({  data: {    currentItemId:"1"  },  onLoad: function (options) {    // 页面初始化 options为页面跳转所带来的参数    var that = this   //这一句不可少,能够调用Page对象的setData({})方法    wx.request({      url: 'https://www.****(你请求的域名).com/json/navList.json', //小程序要求请求的协议必须是https,所以你的服务器后台网站必须https化,而且TLS版本在1.2 以上,过程不难,后续我会写一篇如何部署服务器以及https化和TLS升级的博文      header: {        'content-type': 'application/json'      },      success: function (res) {        that.setData({          navList: res.data        })      }    })  },  clickTap:function(e){    this.setData({      currentItemId:e.currentTarget.dataset.num    })  },  onReady: function () {    // 页面渲染完成  },  onShow: function () {    // 页面显示  },  onHide: function () {    // 页面隐藏  },  onUnload: function () {    // 页面关闭  }})

可以看到clickTap函数的定义。参数e可以用来获取当前点击的子元素信息,e.currentTarget.dataset.num即获取了wxml中当前被点击元素的data-num="{{item.goodsId}}",这样就获取到了被点击元素的goodsId。然后通过this.setData({})方法设置页面data数据中的currentItemId为这个值(默认值为”1”,让第一个子元素是选中的样式)。最后我们在wxml页面中通过{{currentItemId}}获取这个值,用来修改对应子元素的样式。

wxml页面通过三目运算,判断每一个子元素的样式是否需要修改

style="color:{{item.goodsId==currentItemId?'#e98f36':'#000'}}" 这一句通过运算,判断每个子元素是否需要修改,如果它的goodsId等于被点击的元素的id(即currentItemId),就让颜色是#e98f36,否则就是黑色。

<image src="images/{{item.goodsClass}}{{item.goodsId==currentItemId?2:1}}.png"></image>这一句更绝,通过判断每个子元素是不是当前被点击的,直接修改图片的路径来显示不同的图片,达到已点击的样式效果。


这里贴出样式文件wxss,需要看效果的童鞋,复制对应的代码到对应的小程序文件中就行。

.leftNav {  float: left;  width: 160rpx;}.goodsList {  float: right;}.goodsTitle {  min-width: 120rpx;  text-align: center;  line-height: 40rpx;  float: left;  font-size: 30rpx;  padding: 20rpx 20rpx;  background-color: #fafafa;  border-bottom: 2rpx solid lightgray;  border-right: 2rpx solid lightgray;}.goodsTitle>image {  width: 64rpx;  height: 64rpx;}.goodsTitle>span{  display: block;}.goodsTitle>first-child{  border-top: 2rpx solid lightgray;}.goodsImgView{  margin: 0 auto 10rpx;  width: 64rpx;  height: 64rpx;  background-repeat: no-repeat;}

总结:

实现的逻辑有点绕:首先通过JSON数据循环渲染导航栏,然后给每个导航栏一个统一的点击事件函数clickTap,通过这个函数修改当前页面的全局数据currentItemId为被点击元素的goodsId,最后在视图文件中判断当前元素的goodsId是否等于这个值来修改被点击元素的样式。

不得不这样做的根本原因:小程序不能像javascript或者jquery一样获取DOM元素或JQ对象来修改样式,而是通过setData({})方法刷新全局数据,然后回调渲染方法来重绘DOM(懂ReactJS的童鞋应该很熟悉)。全局数据是修改样式的唯一依据,它由点击事件函数修改,但是不像静态wxml每个导航元素都可以定义一个点击事件函数,通过循环遍历的元素只能是调用同一个事件函数(我们定义的clickTap)修改全局数据,所以我们需要获取每个元素的唯一标识(我们定义在JSON中的goodsId)来修改全局数据,最后每个元素根据这个全局数据来修改样式。

-over-


0 0
原创粉丝点击