在项目中需要做一个标题展开框,点击展开才会显示下面的内容。因为多个地方都需要这样的可展开标题,所以做了一个自定义组件。组件需要一个双向绑定的值,控制展开/缩放。于是就思考,父向子可以用props传值,子传父用事件触发,也这样实现了。后来了解到v-model其实就是数据绑定和事件触发的语法糖,和我之前实现的类似,只不过我自己的实现是自己定义个事件名,而v-model的事件是input事件。于是改写成了v-model,使得子组件被复用起来更简单。
父组件中参考如下:(用pug写的)
div.hour-forecast-table
TitleCollapse.title-collapse-wrap(:title="'时段_'+title" v-model="collapse")
div.table-wrap(v-if="collapse")
Table(:columns="columns" :data="tableData" border max-height="500")
TitleCollapse子组件如下
<template lang="pug">
div.title-collapse
div.title-header
div.title-text {{title}}
div.collapse-button(@click="clickCollapseButton")
span.collapse-text {{collapseText}}
Icon(:type="value?'ios-arrow-up':'ios-arrow-down'")
</template>
<script>
export default {
name: "TitleCollapse",
props: {
title: {
type: String
},
value: {
type: Boolean
}
},
data () {
return {
collapse: this.value
}
},
watch: {
value (val) {
this.collapse = val
},
collapse (val) {
this.$emit('input', val)
}
},
computed: {
collapseText () {
if (this.collapse) {
return '收起'
} else {
return '展开'
}
},
},
methods : {
clickCollapseButton () {
this.collapse = !this.collapse
},
}
}
</script>
<style scoped lang="scss">
.title-collapse {
.title-header{
display: -webkit-flex;
justify-content: left;
position: relative;
.title-text{
font-size: 16px;
}
.collapse-button{
font-size: 14px;
color: #1890FF;
position: absolute;
right: 0;
}
}
}
</style>
实现双向绑定有两步,第一步是父传给子,通过props传,v-model在props中是value。然后按按钮子组件里的值变化,不可以直接改props里的值,所以要在data里声明一个新值collapse当中介,赋初始值为value,并且watch value,在value改变时改变collapse。按按钮改变collapse的值,在watch里监控collapse,collapse改变时向外触发input事件,这样就实现了双向绑定。
总结来看,v-model其实就是v-bind和v-on的语法糖。
其实在vue中,在使用v-model绑定数据之后,既绑定了数据,又添加了事件监听,这个事件就是input事件
例如官方文档给出:
可以看出v-modal就是v-bind和v-on的语法糖,自定义组件的实现就是接受了一个value值,在有新的value(比如点击展开/收起按钮的时候新值改变)去触发input事件把新值传出来。这样之前的代码就很好理解了
使用了iview的table,但在table中要自定义一个checkbox选择框,所以需要用到render函数。选择框希望可以双向绑定,发现render函数里需要自己去实现v-model,这就又涉及到了v-model的语法糖,实现如下
tableColumns: [
{
title: '序号',
key: 'id'
},
{
title: '分类',
key: 'targetTypeCategory'
},
{
title: '是否参与计算',
key: 'factor',
render:(h, params) => {
return h('Checkbox', {
style:{
margin:"15px 0px 15px 15px",
display:"block"
},
props: {
value: this.tableData[params.index].factor,
},
on: {
input: (event) => {
this.$set(this.tableData[params.index], 'factor', event);
},
},
})
}
},
{
title: '是否进行公式替换',
key: 'funReplace',
render:(h, params) => {
return h('Checkbox', {
style:{
margin:"15px 0px 15px 15px",
display:"block"
},
props: {
value: this.tableData[params.index].funReplace,
},
on: {
input: (event) => {
this.$set(this.tableData[params.index], 'funReplace', event);
},
},
})
}
}
}
]