创建一个公用的导航navBar组件,让它可以在所有页面使用,比如在index.wxml,引用navBar组件,方法如下
- 1.在需要引用组件的页面中的json中定义这个组件
- //index.json
- {
- "usingComponents": {
- "nav-bar": "/component/navBar/navBar"//自定义组件的名称,组件的路径
- }
- }
- 2.在需要引用组件组件的页面中的wxml中引用这个组件
- //index.wxml
- <nav-bar></nav-bar>
- 3.在组件的json文件中“开启组件”
- //navBar.json
- {
- "component": true
- }
- 4.组件navBar.wxml内部的代码
- //navBar.wxml
- <view>我是navBar</view>
- <!--渲染列表btnChildrenArray,并且绑定了clickTest方法,设置索引为index-->
- <view class="test" wx:for="{{btnChildrenArray}}" bindtap='clickTest' data-index="{{index}}" wx:key="{{item.id}}">
- {{item.name}}
- <!--每个一级菜单的下拉的部分,wx:if根据js中的status[index]的值,来控制是否渲染某一个下拉部分-->
- <view wx:if="{{status[index]}}">
- <!--每一个一级菜单的下拉部分的列表渲染,渲染msg部分-->
- <block wx:for="{{item.msg}}" wx:for-item="todo" wx:key="todo.id">
- <!--wx:if判断todo.url是否成立,成立就渲染navigator标签-->
- <navigator wx:if="{{todo.url}}">
- {{todo.msgName}}
- </navigator>
- <!--wx:if判断todo.methods是否成立,成立就渲染text标签-->
- <text wx:elif="{{todo.methods}}" bindtap='{{todo.methods}}'>{{todo.msgName}}</text>
- <!--wx:if判断todo.isContact,成立就渲染button标签-->
- <button wx:else="{{todo.isContact}}" open-type="contact" class='testClass'>{{todo.msgName}}</button>
- </block>
- </view>
- </view>
- 5.组件的wxss
- //简单的样式,没什么好说的
- .test{
- float: left;
- width: 200rpx;
- height:60rpx;
- line-height: 60rpx;
- text-align: center;
- border:1px solid;
- }
- 6.在组件的js中定义的数据和方法
- //navBar.js
-
- function statusList() {//定义在组件外部的函数,为了让内部的函数每次能够重新调用
- return [false, false, false];
- }
- Component({
- /**
- * 组件的属性列表
- */
- properties: {
-
- },
-
- /**
- * 组件的初始数据
- */
- data: {
- status: statusList(),//调用一次外部函数
- btnChildrenArray: [
- {
- id: 0,
- name: "按钮一",
- msg: [
- {
- id: 10,
- msgName: '000',
- url: '/aa'
- },
- {
- id: 20,
- msgName: '111',
- url: '/bb'
- },
- {
- id: 30,
- msgName: '222',
- url: '/ccaa'
- }
- ]
- },
- {
- id: 1,
- name: "按钮二",
- msg: [
- {
- id: 11,
- msgName: '999',
- url: '/aa'
- },
- {
- id: 12,
- msgName: '111',
- isContact: true
- },
- {
- id: 13,
- msgName: '222',
- url: '/aa'
- }
- ]
- },
- {
- id: 2,
- name: "按钮三",
- status: false,
- msg: [
- {
- id: 21,
- msgName: '888',
- url: '/aa'
- },
- {
- id: 22,
- msgName: '111',
- url: '/aa'
- },
- {
- id: 23,
- msgName: 'test',
- methods: 'test1'
- }
- ]
- },
- ]
- },
-
- /**
- * 组件的方法列表
- */
- methods: {
- test1: function () {//data中methods属性的值对应的函数
- console.log('test1234')
- },
- clickTest: function (e) {
- var index = parseInt(e.currentTarget.dataset.index)//可以console.log(e)查看到获取每次点击的索引值
- var listData = this.data.status//这是定义在data中的数组,第一次点击时为外部函数返回的数组
- //当点击第二次的时候,这里的数组值为上一次存储的值(setData方法),即某一个被改变了的值的数组
- var newStatusList = statusList()//这是调用外部函数,返回的数组
- //第二次点击之后,重新变为全部都是false,重点就在这里,每次返回的都是新的数组,即三个false
- if (listData[index] === false) {//我们要判断的数组值的这个数组,一定是data中定义的数组,即listData,不会判断外部函数返回的数组。因为newStatusList,这是每执行一次点击事件,都会重新调用外部函数,所以每一次走到这里时,它的值都是固定的值,都是外部函数返回的值。而data中的status只会调用一次外部函数,所以,他的值时相对固定的,不会再被外部函数改变
- newStatusList[index] = true//此时改变内部调用函数所返回的数组,如果改变的是listData,那下面的setData也要改成listData,这时如果第二次的index值不一样,那么status里第一次被更改的值无法被恢复,所以这也是有两个数组,且其中一个是每一次都会恢复默认值得原因
- } else {
- //console.log("haha")
- }
- this.setData({
- status: newStatusList//status等于方法返回的数组(即被改变的数组)
- })
- //console.log(newStatusList)
- //console.log(status)
- },
- }
- })
这里面的点击toogle效果的主要实现过程,首先设置下拉的部分全部wx:if="status[index]",status数组中的每一项都为false,根据点击的index值,判断数组中索引为index的的项的值为是否为false,改写为true,即可渲染出下拉部分。
我们要实现第二次点击其他一级菜单的时候,第一次展开的一级菜单下的目录全部隐藏,只渲染当前一级菜单下的目录,就要在每第二次点击的时候,让status的每一项的值恢复为默认的全部为false的状态,然后再改变当前点击的index索引对应的status数组中的值。
但是我们又要实现,连续点击两次同一个按钮时,这个一级菜单有toggle效果,如果像上面那样把status恢复初始值,就不能实现toggle效果。
所以这个时候,需要两个数组,为了方便,可以在外部新建一个函数,返回一个数组,比如statusList()函数返回数组,在data中的status属性调用一次函数,此时可以在点击事件内部定义一个变量newStatusList,重新调用一次外部的函数,返回另一个数组。这时的两个数组的完全独立的。然后如果当前点击索引的值是否为false,就改变newStatusList的值,最后把newStatusList赋值给data中的status属性;如果为true,因为此时的点击事件内部会再一次调用外部函数statusList(),所以newStatusList得值会被恢复为初始状态,所以对应的true,会被改写成false,从而实现了toogle效果
具体的过程可以看上面的注释