Vue——v-model&.sync修饰符&具名插槽&作用域插槽&混入

一、深入理解v-model

v-model 其实就是 v-bind:和v-on: 的语法糖

(1)当事件名为:value及属性名为@input可以合并写为v-model

请求Vue实例数据给组件使用

  <div id="app">
        <p>姓名:<input :value="name" @input="updateName">{{name}}</p>
        <!-- v-model 其实就是 v-bind:和v-on: 的语法糖 -->
        <p>年龄:<input v-model="age">{{age}}</p>
        <hr>
        <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>
        <!-- v-model 其实就是 v-bind:和v-on: 的语法糖 -->
        <b-counter :label="kz.label" v-model="kz.count"></b-counter>
    </div>

(2)使用侦听器侦听myCount的变化,并通过自定义传给绑定事件


        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选项,用于定义组件的属性,有两种方式:1.定义数组,2.定义对象
            //注意:props是只读的,不能修改
            // props:['label','count']
            props: {
                //文本
                label: {
                    type: String,
                    //允许为空
                    required: false,
                },
                //数量
                value: {
                    type: Number,
                    //非空
                    required: true
                },
                //最大值
                maxCount: {
                    type: Number,
                    default: 999
                },
                //最小值
                minCount: {
                    type: Number,
                    default: 1
                }
            },
            //定义数据
            data() {
                return {
                    //将props接收到的value,中转给myCount
                    myCount: this.value
                }
            },
            //监听器
            watch: {
                myCount(val) {
                    // 触发一个自定义事件,事件名称是input,将count的最新值作为事件对象传出去
                    // 注意:自定义事件名称不能使用大写
                    this.$emit('input', val)
                }
            }
        })

        let vm = new Vue({
            el: '#app',
            data: {
                name: '张三',
                age: 20,
                // 衣服
                yf: {
                    label: '衣服',
                    count: 5
                },
                // 裤子
                kz: {
                    label: '裤子',
                    count: 5
                }
            },
            methods: {
                updateName(e) {
                    this.name = e.target.value
                }
            },
        })

二、.sync修饰符

(1)当组件有多个属性需要向父级获取数据并实现双向绑定

使用.sync修饰符绑定属性

    <div id="app">
        <div>衣服:{{yf}},裤子:{{kz}},鞋子:{{xz}}</div>
        <hr>
        <!-- 绑定属性是,采用xx.sync修饰符,可以省略update:xx对应的事件绑定 -->
        <!-- 约定1:属性绑定必须是xx.sync -->
        <b-counter :yf.sync="yf" @update:yf="yf=$event" :kz.sync="kz" :xz.sync="xz"></b-counter>
    </div>

(2)修改的数据在data里转一下,监听并自定义事件$emit

注意:在事件名前需要加update: this.$emit('update:xx',val)

    Vue.config.productionTip = false
        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){
                    // 约定2:自定义事件必须是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)使用具名插槽在组件中写template标签,绑定属性

绑定的属性是插槽name的值,template属性写法有两种:
①v-slot:name
②#name
    <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>

(3)具名插槽就是给插槽绑定name属性并给一个值,这个值用来在template绑定

这样在对应name值的template标签中书写的内容出现在对应的插槽中

    Vue.config.productionTip = false
        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',

        })

四、作用域插槽

(1)在组件template标签中,用v-slot:list="scope"

①scope用于接收插槽暴露的值,进行操作
②v-slot:list="scope可以简写为#list="scope”
③这个list是具名插槽name绑定的名称**
⑤注意:作用域插槽必须是具名插槽

总结:通过slot插槽把数据给你暴露给你,你自己去根据数据操作自己想要的效果

 <div id="app">
        <!-- 作用域插槽必须是具名插槽;在作用插槽上,可以通过v-bind:绑定属性,绑定的属性,通过指定的作用域变量去接收 -->
        <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>

(2)给组件模板slot插槽通过v-bind:绑定属性,把数据暴露出来

   Vue.config.productionTip = false
        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
                }
            },
        })

五、混入及混入ajax的基本操作

(1)Vue.mixin({})里面的数据和方法可直接在容器中

 <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>
        <button @click="getSubjects">请求课程数据</button>
        <div>
            {{subjects}}
        </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>

(2)两个vue实例有很多相同的代码块,则可以把它放到Vue.mixin里

①vue.mixin里可以放计算属性、公共的方法、公共的监听器、公共的数据、公共的行为等,先混合给Vue实例。将来不管创造多少vue实例都可以使用,当然也可以写自己的。
②vue.mixin生命周期函数的执行顺序,是先执行混入的生命周函数期,再执行自己的生命周期函数
③如果和vue.mixni里有冲突,则实行就近原则

(3)可以在vue.mixin方法里封装ajax请求

这样在别的vue实例中就可以直接使用这个封装过的方法
   Vue.config.productionTip = false
        //给所有的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}岁`)
                },
                //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
                }
            },
            watch:{
                age(val){
                    if(val>100){
                        alert('年龄不能超过100岁')
                        this.age = 100
                    }
                }
            },
            mounted() {
                console.log('mixin:组件挂载完成');
            },
        })

        new Vue({
            el:'#app1',
            data() {
                return {
                    car:{
                        name:'奔驰',
                        price:'100W'
                    },
                    //课程数组
                    subjects:[]
                }
            },
            methods: {
                async getSubjects(){
                    let {data} = await this.$get('http://www.bingjs.com:81/Subject/GetSubjectsConditionPages')
                    this.subjects = data
                }
            },
            // 注意:先执行混入的生命周期,再执行自己的生命周期
            mounted() {
                console.log('app1:组件挂载完成');
            },
        })
        new Vue({
            el:'#app2',
            data() {
                return {
                    plane:{
                        name:'波音747',
                        price:'100Y'
                    }
                }
            },
        })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容