创建一个公用的导航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效果
具体的过程可以看上面的注释