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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Just_Do_It_1993/article/details/69392386

我们在做微信小程序的时候,往往需要做导航栏,效果是:点击导航栏的子元素,显示对应的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-


猜你喜欢

转载自blog.csdn.net/Just_Do_It_1993/article/details/69392386