美文网首页
Vue——.sync修饰符 & 具名插槽 & 作用域插槽 & m

Vue——.sync修饰符 & 具名插槽 & 作用域插槽 & m

作者: 叽里咕呱 | 来源:发表于2021-12-06 16:21 被阅读0次

    一、深入理解v-model

    v-model 其实就是 v-bind: 和 v-on: 的语法糖。
    将自定义组件,绑定数据的属性改成value,监听事件的名称改成input,也可以使用v-model简写形式。

    <div id="app">
        <ul class="list">
            <li>{{yf.label}}--{{yf.count}}</li>
            <li>{{kz.label}}--{{kz.count}}</li>
        </ul>
        <b-counter :label="yf.label" :value="yf.count" @input="yf.count=$event"></b-counter>
        <b-counter :label="kz.label" v-model="kz.count"></b-counter>
    </div>
    
    Vue.component('b-counter', {
        template: `
                <div class="counter">
                    <div class="label">{{label}}</div>
                    <div class="btns">
                        <button @click="myCount--" :disabled="myCount===minCount">-</button>
                        <input readonly class="text" type="text" :value="myCount">
                        <button @click="myCount++" :disabled="myCount===maxCount">+</button>
                    </div>
                </div>
                `,
        props: {
            //文本
            label: {
                type: String,
                required: false,
            },
            //数量
            value: {
                type: Number,
                required: true
            },
            //最大值
            maxCount: {
                type: Number,
                default: 999
            },
            //最小值
            minCount: {
                type: Number,
                default: 1
            }
        },
        //定义数据
        data() {
            return {
                myCount: this.value
            }
        },
        //监听器
        watch: {
            myCount(val) {
                // 触发一个自定义事件,事件名称是input
                this.$emit('input', val)
            }
        }
    })
    
    let vm = new Vue({
        el: '#app',
        data: {
            // 衣服
            yf: {
                label: '衣服',
                count: 5
            },
            // 裤子
            kz: {
                label: '裤子',
                count: 5
            }
        }
    })
    

    效果:

    二、.sync修饰符

    绑定属性采用:xx.sync修饰符,可以省略update:xx对应的事件绑定。约定①:属性绑定必须是xx.sync;约定②:自定义事件必须是update:xx。
    如果触发的事件名称是update:属性名,那么就可以使用.sync修饰符简化调用的过程。
    总结:如果组件只回传一份数据,用v-model。如果组件回传多份数据,用.sync修饰符。

    <div id="app">
        <div>衣服:{{yf}},裤子:{{kz}},鞋子:{{xz}}</div>
        <!-- 属性绑定必须是:xx.sync -->
        <!-- :yf.sync="yf" @update:yf="yf=$event"可以简写成 :yf.sync="yf" -->
        <b-counter :yf.sync="yf" @update:yf="yf=$event" :kz.sync="kz" :xz.sync="xz"></b-counter>
    </div>
    
    Vue.component('b-counter', {
        template: `
            <div>
                <div class="counter">
                    <div class="label">衣服:</div>
                    <div class="btns">
                        <button @click="yfCount--">-</button>
                        <input readonly class="text" type="text" :value="yfCount">
                        <button @click="yfCount++">+</button>
                    </div>
                </div>
                <div class="counter">
                    <div class="label">裤子:</div>
                    <div class="btns">
                        <button @click="kzCount--">-</button>
                        <input readonly class="text" type="text" :value="kzCount">
                        <button @click="kzCount++">+</button>
                    </div>
                </div>
                <div class="counter">
                    <div class="label">鞋子:</div>
                    <div class="btns">
                        <button @click="xzCount--">-</button>
                        <input readonly class="text" type="text" :value="xzCount">
                        <button @click="xzCount++">+</button>
                    </div>
                </div>
            </div>
        `,
        props: ['yf', 'kz', 'xz'],
        data() {
            return {
                yfCount: this.yf,
                kzCount: this.kz,
                xzCount: this.xz
            }
        },
        watch:{
            yfCount(val){
                // 自定义事件必须是update:xx
                this.$emit('update:yf',val)
            },
            kzCount(val){
                this.$emit('update:kz',val)
            },
            xzCount(val){
                this.$emit('update:xz',val)
            }
        }
    })
    new Vue({
        el: '#app',
        data: {
            //衣服数量
            yf: 5,
            //裤子数量
            kz: 5,
            //鞋子数量
            xz: 5
        }
    })
    

    三、插槽

    1、具名插槽

    具名插槽:在组件内部通过slot标签定义插槽,再通过name属性给插槽定义名字,这样的插槽称之为具名插槽。
    插槽的默认名称是:default。如果有多个插槽,允许其中一个插槽不定义名称。
    在template标签中采用v-slot:插槽名称的方式,指定内容在哪一个具体的插槽中呈现。#是v-slot:的简写。

    <div id="app">
        <b-box>
            <!-- 在template组件中采用v-slot:插槽名称的方式,指定使用哪个插槽 -->
            <template v-slot:house>
                <div>有5套房子</div>
            </template>
            <!-- #是v-slot:的简写 -->
            <template #car>
                <div>有8辆汽车</div>
            </template>
            <template v-slot:money>
                <div>有3千万存款</div>
            </template>
        </b-box>
    </div>
    
    Vue.component('b-box', {
        template: `
            <div class="box">
                <div class="item">
                    <h2>房产信息</h2>
                    <slot name="house"></slot>
                </div>
                <div class="item">
                    <h2>车辆信息</h2>
                    <slot name="car"></slot>
                </div>
                <div class="item">
                    <h2>存款信息</h2>
                    <slot name="money"></slot>
                </div>
            </div>
        `
    })
    new Vue({
        el: '#app',
    })
    

    2、作用域插槽

    作用域插槽必须是具名插槽;在作用域插槽上,可以通过v-bind:绑定属性,绑定的属性通过指定的作用域变量(通常会定义scope变量)去接收。

    <div id="app">
        <b-box>
            <template v-slot:list="scope">
                <button @click="priceDown(scope.list,scope.index)">降价</button>
                <button @click="priceUp(scope.list,scope.index)">加价</button>
                <button @click="scope.list.splice(scope.index,1)">删除</button>
            </template>
        </b-box>
    </div>
    
    Vue.component('b-box', {
        template:`
        <div>
            <ul>
                <li v-for="(item,index) in list" :key="index">
                    <span>{{item.id}}-{{item.name}}-{{item.price}}</span>
                    <slot name="list" v-bind:index="index" v-bind:list="list"></slot>
                </li>
            </ul>
        </div>
        `,
        data() {
            return {
                list:[
                    {
                        id:1001,
                        name:'苹果手机',
                        price:5999
                    },
                    {
                        id:1002,
                        name:'华为手机',
                        price:6999
                    },
                    {
                        id:1003,
                        name:'小米手机',
                        price:7999
                    },
                    {
                        id:1004,
                        name:'三星手机',
                        price:8999
                    }
                ]
            }
        }
    })
    new Vue({
        el:'#app',
        methods: {
            priceDown(list,index){
                list[index].price-=1000
            },
            priceUp(list,index){
                list[index].price+=1000
            }
        },
    })
    

    四、mixin混入

    混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。mixin()方法的参数是配置对象,Vue实例可以配置的东西,它都可以配置。比如:数据,方法,生命周期钩子函数,计算属性,侦听器,过滤器,等等...
    全局混入的内容,之后创建的所有Vue实例包括组件实例都将拥有。在创建Vue实例时,会将mixin里面的成员跟Vue实例自身的成员进行合并,如果冲突了,最终采用Vue实例身上的成员。
    特别注意:生命周期钩子不是合并,是叠加执行,是先执行mixin里面的生命周期钩子,再执行Vue实例里面的生命周期钩子。

    <div id="app1">
        <p>姓名:<input type="text" v-model="name"></p>
        <p>年龄:<input type="text" v-model.number="age"><button @click="age++">++</button></p>
        <p>性别:<input type="text" v-model="sex"></p>
        <p>税前薪资:<input type="text" v-model="salary">税后薪资:<input type="text" :value="salary2"></p>
        <button @click='sayHi'>sayHi</button>
        <div>汽车信息:{{car}}</div>
    </div>
    <hr>
    <div id="app2">
        <p>姓名:<input type="text" v-model="name"></p>
        <p>年龄:<input type="text" v-model.number="age"><button @click="age++">++</button></p>
        <p>性别:<input type="text" v-model="sex"></p>
        <p>税前薪资:<input type="text" v-model="salary">税后薪资:<input type="text" :value="salary2"></p>
        <button @click='sayHi'>sayHi</button>
        <div>飞机信息:{{plane}}</div>
    </div>
    
    //全局混入,给所有的Vue实例混入统一的成员 -- 注意:必须要先执行
    Vue.mixin({
        data() {
            return {
                name: '',
                age: 0,
                sex: '男',
                salary: 1000
            }
        },
        computed: {
            salary2() {
                return this.salary * 0.88
            }
        },
        methods: {
            sayHi() {
                alert(`大家好!我叫${this.name},性别是${this.sex},今年${this.age}岁`)
            }
        },
        watch: {
            age(val) {
                if (val > 100) {
                    alert('年龄不能超过100岁')
                    this.age = 100
                }
            }
        },
        mounted() {
            console.log('mixin:组件挂载完成');
        },
    })
    // 创建第一个Vue的实例--操作的容器是#app1
    new Vue({
        el: '#app1',
        data() {
            return {
                car: {
                    name: '奔驰',
                    price: '100W'
                }
            }
        },
        // 注意:先执行混入的生命周期,再执行自己的生命周期
        mounted() {
            console.log('app1:组件挂载完成');
        },
    })
    // 创建第二个Vue的实例--操作的容器是#app2
    new Vue({
        el: '#app2',
        data() {
            return {
                plane: {
                    name: '波音747',
                    price: '100Y'
                }
            }
        },
    })
    

    效果:

    五、混入ajax的基本操作

    ajax请求相关的操作,也可以通过mixin混入给Vue。

    <div id="app1">
        <button @click="getSubjects">请求课程数据</button>
        <div>
            {{subjects}}
        </div>
    </div>
    
    Vue.mixin({
        methods: {
            //get请求
            async $get(url, params) {
                let { data } = await axios.get(url, { params })
                return data
            },
            //post请求
            async $post(url, params) {
                let { data } = await axios.post(url, params)
                return data
            }
        }
    })
    
    new Vue({
        el: '#app1',
        data() {
            return {
                //课程数组
                subjects: []
            }
        },
        methods: {
            async getSubjects() {
                let { data } = await this.$get('http://www.bingjs.com:81/Subject/GetSubjectsConditionPages')
                this.subjects = data
            }
        }
    })
    

    相关文章

      网友评论

          本文标题:Vue——.sync修饰符 & 具名插槽 & 作用域插槽 & m

          本文链接:https://www.haomeiwen.com/subject/ofngxrtx.html