聊一聊vue的sync与插槽是什么

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使用时只需要简单修改就可以了

  1. 把v-model改为单向绑定并加一个修饰符sync
<k-pagination :pages.sync="uPages"  :page.sync="uPage"></k-pagination>
  1. 然后把组件内的model删掉然后对$emit里的值做一个修改
修改前(需要model)
gotoPage(p) {
	this.$emit("changpage", p);
},

修改后(不需要model)
gotoPage(p) {
	this.$emit("update:page", p);
},

注释 这里的update是固定的,后边是你要更新的值,逗号后边是你要给更新的值绑定的数据

我们使用sync完成双向数据绑定就完成了

我们来看一下我们在v-model上做了哪些修改呢

  1. 传值的时候增加修饰符,单向数据绑定即可
  2. 回传的时候不需要自定义事件,直接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>`,

在这里插入图片描述
注意:

  1. 传递过来的值,是一个对象,所以要 点语法 来调用
  2. 一个插槽就需要一个template
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值