sync 修饰符是一个非常重要的知识点,将页面拆分成一个个组件的时候就经常用到 sync 修饰符。比如你做过 vue+element-ui 的管理系统,要对分页组件拆分成一个独立的子组件这个时候一定会使用到 sync 修饰符
为了深入理解,我们需要两个组件 myDialog.vue(对话框组件)
与 test.vue
。其中 myDialog.vue
为子组件, test.vue
为父组件。需要完成的功能:当我们点击父组件的显示按钮会弹出对话框组件。并且当我们点对话框的“确定”或“取消”按钮也要将子组件隐藏。实际效果就是模仿 element-ui 制作一个自己的 dialog 组件。
- myDialog.vue 子组件
<template>
<div>
<div>
<h1>Hello</h1>
<div>
<button>取消</button>
<button>确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'myDialog',
}
</script>
- test.vue 父组件
<template>
<div>
<button>点击显示对话框</button>
<my-dialog />
</div>
</template>
<script>
import myDialog from './myDialog'
export default {
name: 'test',
components: {
myDialog,
},
}
</script>
解决思路:
- 我们要在父组件中定义一个 isShow 变量默认值为false,并将 isShow 传给对话框组件,整个对话框的显示和隐藏都是由父组件的 isShow 来决定
- 点击父组件的显示按钮将 isShow 进行取反。
- 那么点击对话框的“确定”或者“显示”的时候我们就需要改变父组件的 isShow。(给对话框的按钮绑定点击事件,点击利用 发出一个 update 事件)
补充:你可能会想在子组件中直接修改,父组件传过来的 isShow 岂不是更加简单。但是父组件传给子组件的 prop 是单向数据流,数据是只读的,不允许修改。强行修改不仅没有效果并且控制台会报错
所以代码可以修改如下:
<!-- 父组件 -->
<template>
<div>
<button id="btn" @click="isShow = !isShow">点击显示对话框</button>
<my-dialog :isShow="isShow" @update="isShow = $event" />
</div>
</template>
<script>
import myDialog from './myDialog'
export default {
name: 'test',
data() {
return {
isShow: false,
}
},
components: {
myDialog,
},
}
</script>
<!-- 对话框组件 -->
<template>
<div id="test" v-show="isShow">
<div class="box">
<h1>Hello</h1>
<div>
<button @click="updateShow">取消</button>
<button @click="updateShow">确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'myDialog',
props: {
isShow: {
type: Boolean,
default() {
return false
},
},
},
methods: {
},
}
</script>
关于事件中的 $event
- 如果是js原生事件,那么 $event 为”事件对象“。
- 如果是子组件利用 $emit() 发出的自定事件,那么 $event 表示自定义事件传过来的参数
- 所以如上代码可以直接在组件标签上进行赋值:
@update="isShow = $event"
为了更加能够语义化,更加清楚的表示需要修改的数据,可将部分代码修改如下:
- 子组件
- updateShow() {
//你可以将添加的 :isShow 理解为标识
//这也是在 sync 做铺垫,要使用 sync 子组件比如遵从如下写法(‘update:xx’)
this.$emit(‘update:isShow’, !this.isShow)
},
- updateShow() {
- 父组件
- <!– 监听子组件发出的事件也要携带 :isShow 标识 –>
<my-dialog :isShow=”isShow” @update:isShow=”isShow = $event” />
- <!– 监听子组件发出的事件也要携带 :isShow 标识 –>
- 补充:这里的
update:xx
其中 update 其实不是固定写法,你也可以换成其他字符,比如u:xx
,父子组件都要同时改为u
。但是!!当你使用sync
修饰符的时候update:
就是一个固定的写法,为了方便update:
我们一般都认为这是固定的写法,不管有没有使用 sync 修饰符
sync 修饰符:
sync
修饰符就是用于简化父组件 @update:isShow="isShow = $event"
这一行代码而诞生的。
使用:
<my-dialog :isShow.sync="isShow" />
使用了 sync 修饰符,vue会自动帮你编译出 @update:isShow="isShow = $event"
这一行代码。
注意!!子组件中的写法还是一样需要携带标识:this.$emit('update:isShow', !this.isShow)
通过如上的分析你现在一定能理解 element-ui 中 dialog 组件为什么会使用 :visible.sync=""
。你也能写出与 element-ui 类似的组件
<el-dialog
:visible.sync="dialogVisible"
</el-dialog>
最终完整代码
<!-- 父组件 -->
<template>
<div>
<button id="btn" @click="isShow = !isShow">点击显示对话框</button>
<my-dialog :isShow.sync="isShow" />
</div>
</template>
<script>
import myDialog from './myDialog'
export default {
name: 'test',
data() {
return {
isShow: false,
}
},
components: {
myDialog,
},
}
</script>
<style>
#btn {
background-color: sandybrown;
color: #fff;
border: none;
margin: 50px;
height: 35px;
padding: 0 20px;
}
</style>
<!-- 子组件 -->
<template>
<div id="test" v-show="isShow">
<div class="box">
<h1>Hello</h1>
<div>
<button @click="updateShow">取消</button>
<button @click="updateShow">确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'myDialog',
props: {
isShow: {
type: Boolean,
default() {
return false
},
},
},
methods: {
updateShow() {
this.$emit('update:isShow', !this.isShow)
},
},
}
</script>
<style>
#test {
position: absolute;
z-index: 10px;
background-color: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
#test .box {
width: 400px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow: 1px 1px 10px #999;
background-color: #fff;
}
#test .box div {
position: absolute;
bottom: 0;
right: 0;
}
#test .box div button {
width: 80px;
height: 35px;
margin-right: 10px;
border: none;
}
</style>