sync
为什么要用sync:
我们在上一篇中实现了分页组件传参的功能,但如果需要双向数据绑定的话,使用v-model会比较麻烦,不推荐使用,所以使用sync就比较方便一点
为什么v-model双向数据绑定不推荐使用:
因为它隐藏了太多细节,会让我们使用的时候,操作空间变小,出现错误的时候,不容易排查,绑定不了多个prop
为什么推荐使用sync:
.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
下面我们通过代码对比来了解sync
通过v-model实现
<style>
.pagination {
margin: 20px 0;
}
.pagination a {
padding: 5px 12px;
border: 1px solid #3ba9ff;
text-decoration: none;
margin: 5px;
}
.pagination a.active {
background: #3ba9ff;
color: white;
}
</style>
<body>
<div id="app">
<ul>
<li v-for="user of showUsers" :key="user.id">
{{user.name}}
</li>
</ul>
<k-pagination :pages="uPages" v-model="uPage"></k-pagination>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("k-pagination", {
props: ['pages', 'uPage'],
model:{
prop:"uPage",
event:"changpage",
},
template: ` <div class="pagination">
<a href="javascript:;" @click="prev">上一页</a>
<a href="" v-for="p of pages" @click.prevent="gotoPage(p)" :class="{active: uPage===p}"> {{p}} </a>
<a href="javascript:;" @click="next">下一页</a>
</div>`,
methods: {
gotoPage(p) {
this.$emit("changpage", p);
},
prev() {
if (this.uPage - 1 > 0) {
this.$emit("changpage", this.uPage - 1);
}
},
next() {
if (this.uPage < this.pages) {
this.$emit("changpage", this.uPage + 1);
}
},
},
})
let app = new Vue({
el: '#app',
data: {
users: [
{ id: 1, name: '光达' },
{ id: 2, name: '小涛' },
{ id: 3, name: '小冯' },
{ id: 4, name: '小金' },
{ id: 5, name: '小宝' },
{ id: 6, name: '祥子' },
{ id: 7, name: '大武' },
],
uPage: 1,
prePage: 2,
},
computed: {
uPages() {
return Math.ceil(this.users.length / this.prePage);
},
showUsers() {
let start = (this.uPage - 1) * this.prePage;
return this.users.slice(start, start + this.prePage);
}
}
});
</script>
</body>
通过sync使用时只需要简单修改就可以了
- 把v-model改为单向绑定并加一个修饰符sync
<k-pagination :pages.sync="uPages" :page.sync="uPage"></k-pagination>
- 然后把组件内的model删掉然后对$emit里的值做一个修改
修改前(需要model)
gotoPage(p) {
this.$emit("changpage", p);
},
修改后(不需要model)
gotoPage(p) {
this.$emit("update:page", p);
},
注释 这里的update是固定的,后边是你要更新的值,逗号后边是你要给更新的值绑定的数据
我们使用sync完成双向数据绑定就完成了
我们来看一下我们在v-model上做了哪些修改呢
- 传值的时候增加修饰符,单向数据绑定即可
- 回传的时候不需要自定义事件,直接update更新数据
插槽
什么是插槽:
默认情况下,组件模板解析后会替换整个组件内容,如果我们想在组件引用被包含的内容,可以通过vue提供的内置组件slot来获取
如果我们直接在组件内部去写的话,不会被加载,会被组件内部的替换掉
<k-pagination :pages.sync="uPages" :page.sync="uPage">
<span>我是插槽</span>
</k-pagination>
浏览器反馈上边我们就不会看到span标签里的内容
但是我们可以通过slot获取到它
template: ` <div class="pagination">
...
<slot></slot>
</div>`,
浏览器反馈上边就得到了
这就好像是一个函数一样,在模板里去调用
但是如果我们有多个模板的情况就需要再加一点处理了
比如说
<k-pagination :pages.sync="uPages" :page.sync="uPage">
<span>当前页数</span>
<span>总页数</span>
</k-pagination>
浏览器反馈
所以我们这个时候需要给插槽写一个名字 也就是具名插槽
<k-pagination :pages.sync="uPages" :page.sync="uPage" >
<span slot="header">当前页数</span>
<span slot="footer">总页数</span>
</k-pagination>
template: ` <div class="pagination">
<slot name="header"></slot>
...
<slot name="footer"></slot>
</div>`,
浏览器反馈
如果不想写名字,但又不得不写的话,可以把名字写为default 这样调用的时候直接写slot就可以了,这是默认的名字。
如果我们的插槽需要数据的话
我们就需要 组件给组件内部的插槽去传递,插槽在哪个组件内,它的作用域就仅限于这个组件内,方式和之前的父传子是一样的
<k-pagination :pages.sync="uPages" :page.sync="uPage" >
<template v-slot:header="page">
<span>当前页数 {{page.page}} </span>
</template>
<template v-slot:footer="pages">
<span>总页数 {{pages.pages}} </span>
</template>
</k-pagination>
...
template: ` <div class="pagination">
<slot name="header" :page="page"></slot>
...
<slot name="footer" :pages="pages"></slot>
</div>`,
注意:
- 传递过来的值,是一个对象,所以要 点语法 来调用
- 一个插槽就需要一个template