首先看看全文要实现的效果图:
说明:在“发布我的闲置物品”这个页面里,有一个所属分类的选项,我选择使用小程序原生的picker来做普通的滚动选择。这里,实现“发布我的闲置物品”这个页面的/src/pages/createGoods/index.vue作为父组件,另外封装/src/components/selectBox.vue作为子组件来实现滚动选择器。父组件将需要渲染的可选值(例如:电子产品、运动器材等)通过props传递给子组件。然后子组件将被选中的值通过$emit返回给父组件。
在父组件中,首先获取所有分类,得到数据形式如下:
为了 不分散注意,以下展示的代码只贴出分类目录相关部分,父组件/src/pages/createGoods/index.vue代码如下:
<template>
<div class="wrapper">
<div class="properties">
<div>
<span class="mark"> * </span>
<label class="title">所属分类:</label>
<selectBox @selectedValue="updateBelongsCategory" :selectList="categoryList" ></selectBox>
</div>
</div>
</div>
</template>
<script>
import selectBox from '@/components/selectBox'
export default {
data () {
return {
categoryList: [],
belongsCategory: 0
}
},
components: {
selectBox
},
methods: {
// 接收子组件传值,获取选中的分类ID
updateBelongsCategory (val) {
this.belongsCategory = val
},
// 获取所有分类
async initCategoryData () {
await this.$http.get({
'url': '/category/all'
}).then(res => {
// 使用nextTick同步视图更新
this.$nextTick(() => {
// 为了让子组件更加通用,这里将category_id更换为code,在子组件中将通过code来获取分类id
let arr = JSON.parse(JSON.stringify(res).replace(/category_id/g, 'code'))
this.categoryList = arr
})
})
}
},
onLoad () {
this.initCategoryData()
}
}
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">
.wrapper
.properties
font-size: 34rpx
&>div
padding: 20rpx 0
display: flex
line-height: 150%
&>input
width: 100%
border: 1rpx solid #f4f4f4
text-align: center
padding: 10rpx 0
.mark
color: red;
margin-right: 10rpx;
.title
white-space: nowrap
</style>
在父组件中传递给子组件的数据是object array类型的,我们在滚动选择器中要显示的名称就是该对象数组中每个对象的name属性,选中后我们应该将被选中对象的code属性值回传给父组件。根据微信开放文档,可以使用mode=selector,range来表示选择器的数据域,当range是个object array类型的时候,可以通过range-key来指定object中key的值作为显示内容。子组件/src/components/selectBox.vue代码如下:
<template>
<div class="select_box">
<picker mode="selector" :value="selectList[index].code" :range="selectList" range-key='name' @change="pickerChange">
<view class="picker">
{{selectList[index].name}}
</view>
</picker>
</div>
</template>
<script>
export default {
props: {
'selectList': {
type: Array
}
},
data () {
return {
index: 0// 数组下角标
}
},
methods: {
// 改变选项
pickerChange (e) {
let value = e.mp.detail.value
this.index = value
// 发布自定义事件向父组件使传递数据
this.$emit('selectedValue', this.selectList[value].code)
}
}
}
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">
.select_box
width: 100%
text-align: center
border: 1rpx solid #f4f4f4
</style>
对上述代码作说明:
在子组件/src/components/selectBox.vue中,接收父组件传递过来的对象数组类型数据:selectList,在picker标签中通过range指定selectList的值提供用户选择,range-key指定selectList数组中每个对象的name属性值作为显示内容。用index记录被选中对象在数组中的下角标,index初始值为0。value值为被选中对象的code属性值。
<picker mode="selector" :value="selectList[index].code" :range="selectList" range-key='name' @change="pickerChange">
<view class="picker">
{{selectList[index].name}}
</view>
</picker>
当value值发生变化时,会触发change事件。也就是用户选择完毕时会触发change绑定的事件pickerChange()。在pickerChange()方法中,e.mp.detail.value代表当前被选中对象在数组中的下角标。通过下角标可以获取当前被选中对象的code属性值。再通过$emit(event,arg)方法,绑定自定义event事件:selectedValue事件,并将code值作为参数传递给父组件。
methods: {
// 改变选项
pickerChange (e) {
let value = e.mp.detail.value
this.index = value
// 发布自定义事件向父组件使传递数据
this.$emit('selectedValue', this.selectList[value].code)
}
}
父组件通过在使用子组件时,@event(即@selectedValue="父组件方法")即可获取到子组件传递过来的值。
// 父组件中使用子组件时,监听了自定义事件:selectedValue事件
<selectBox @selectedValue="updateBelongsCategory" :selectList="categoryList" ></selectBox>
// 父组件方法updateBelongsCategory
methods: {
// 接收子组件传值,获取选中的分类ID
updateBelongsCategory (val) {
this.belongsCategory = val
}
}