vue-v-model的深入了解&sync修飾符&插槽&混入

一誓斥、v-model

1只洒、v-model的含義

v-model就是vue的雙向綁定的指令,能將頁(yè)面上控件輸入的值同步更新到相關(guān)綁定的data屬性劳坑,也會(huì)在更新data綁定屬性時(shí)候毕谴,更新頁(yè)面上輸入控件的值。

2距芬、v-model的基礎(chǔ)用法

(1)v-model 指令在表單 <input>涝开、<textarea> 及 <select> 元素上創(chuàng)建雙向數(shù)據(jù)綁定。它會(huì)根據(jù)控件類(lèi)型自動(dòng)選取正確的方法來(lái)更新元素框仔。
(2)v-model 本質(zhì)上不過(guò)是語(yǔ)法糖舀武。它負(fù)責(zé)監(jiān)聽(tīng)用戶的輸入事件以更新數(shù)據(jù),并對(duì)一些極端場(chǎng)景進(jìn)行一些特殊處理离斩。
(3)v-model 在內(nèi)部為不同的輸入元素使用不同的 property 并拋出不同的事件:
text 和 textarea 元素使用 value property 和 input 事件银舱;
checkbox 和 radio 使用 checked property 和 change 事件;
select 字段將 value 作為 prop 并將 change 作為事件跛梗。

3寻馏、使用示例

當(dāng)你在input輸入框中輸入內(nèi)容的時(shí)候,上面p標(biāo)簽里面的數(shù)據(jù)實(shí)時(shí)發(fā)生變化(實(shí)際上是name和age兩個(gè)數(shù)據(jù)發(fā)生了響應(yīng)式變化)核偿。相反改變代碼中的name和age值诚欠,input輸入框中值也會(huì)實(shí)時(shí)變化。
其實(shí)現(xiàn)原理如下:

<div id="app">
       <p>姓名:<input :value="name" @input="updateName">{{name}}</p>
        <!-- v-model 其實(shí)就是v-bind: 和 v-on: 的語(yǔ)法糖 -->
        <p>年齡:<input :value="age" @input="updateAge">{{age}}</p>
    </div>
<script>
        new Vue({
            el: '#app',
            data: {
                name: '張三',
                age: 20,
            },
            methods: {
                updateName(e) {
                    this.name = e.target.value;
                },
                updateAge(e){
                    this.age = e.target.value;
                }
            },
        })
    </script>

實(shí)現(xiàn)效果如下:


image.png

實(shí)現(xiàn)原理:
①首先input輸入框通過(guò)屬性綁定:value="name"&:value="age"得到響應(yīng)數(shù)據(jù)name&age.
②定義兩個(gè)函數(shù),通過(guò)e.target得到input框中的value值轰绵。
③最后通過(guò)input輸入框@input事件監(jiān)聽(tīng)粉寞,綁定兩個(gè)函數(shù)(updateName,updateAge)左腔,將input框中的value值傳給name&age唧垦。

vue中的v-model能夠?qū)崿F(xiàn)數(shù)據(jù)的雙向綁定,也是vue的最突出的優(yōu)勢(shì)翔悠。
v-model實(shí)際上是v-bind: 和 v-on:的語(yǔ)法糖业崖。它的實(shí)現(xiàn)原理主要包括屬性綁定和事件監(jiān)聽(tīng)兩部分野芒。
具體使用如下:

<div id="app">
       <p>姓名:<input v-model="name">{{name}}</p>
        <!-- v-model 其實(shí)就是v-bind: 和 v-on: 的語(yǔ)法糖 -->
        <p>年齡:<input v-model="age">{{age}}</p>
    </div>
<script>
        new Vue({
            el: '#app',
            data: {
                name: '張三',
                age: 20,
            },
        })
    </script>

實(shí)現(xiàn)效果與v-bind: + v-on:相同:


image.png

二蓄愁、sync修飾符

在有些情況下,我們可能需要對(duì)一個(gè) prop 進(jìn)行“雙向綁定”狞悲。但真正的雙向綁定會(huì)帶來(lái)維護(hù)上的問(wèn)題撮抓,因?yàn)樽咏M件可以變更父組件,且在父組件和子組件兩側(cè)都沒(méi)有明顯的變更來(lái)源摇锋。
當(dāng)我們需要在某個(gè)標(biāo)簽中綁定多個(gè)屬性時(shí)丹拯,就選擇使用.sync修飾符。
.sync修飾符的約定:
① 屬性綁定必須是xx.sync
② 自定義事件必須是update:xx格式
③ 采用xx.sync修飾符荸恕,可以省略u(píng)pdate:xx對(duì)應(yīng)的事件綁定
使用方法如下:

<div id="app">
        <div>
            衣服:{{yf}},褲子:{{kz}},鞋子:{{xz}}
        </div>
        <hr>
        <!-- 綁定屬性是乖酬,采用xx.sync修飾符,可以省略u(píng)pdate:xx對(duì)應(yīng)的事件綁定 -->
        <!-- 約定1:屬性綁定必須是xx.sync -->
        <b-counter :yf.sync="yf" :kz.sync="kz" :xz.sync="xz"></b-counter>
    </div>
<script>
        Vue.config.productionTip = false
        Vue.component('b-counter', {
            template: `
                <div>
                    <div class='conter'>
                       <div class='label'>衣服</div>
                       <div class='btns'>
                           <button @click='yfCount--' class='btn'>-</button>
                           <input type='text' readonly class='txt' :value='yfCount'>
                           <button @click='yfCount++' class='btn'>+</button>
                       </div>
                    </div>
                    <div class='conter'>
                       <div class='label'>褲子</div>
                       <div class='btns'>
                           <button @click='kzCount--' class='btn'>-</button>
                           <input type='text' readonly class='txt' :value='kzCount'>
                           <button @click='kzCount++' class='btn'>+</button>
                       </div>
                    </div><div class='conter'>
                       <div class='label'>鞋子</div>
                       <div class='btns'>
                           <button @click='xzCount--' class='btn'>-</button>
                           <input type='text' readonly class='txt' :value='xzCount'>
                           <button @click='xzCount++' class='btn'>+</button>
                       </div>
                    </div>
                </div>`,
            props: ['yf', 'kz', 'xz'],
            data() {
                return {
                    yfCount: this.yf,
                    kzCount: this.kz,
                    xzCount: this.xz,
                }
            },
            // 監(jiān)聽(tīng)器
            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: {
                // 衣服數(shù)量
                yf: 5,
                // 褲子數(shù)量
                kz: 5,
                // 鞋子數(shù)量
                xz: 5
            }
        })
    </script>

三融求、插槽

插槽的含義
插槽就是子組件中的提供給父組件使用的一個(gè)占位符咬像,用<slot></slot> 表示,父組件可以在這個(gè)占位符中填充任何模板代碼生宛,如 HTML县昂、組件等,填充的內(nèi)容會(huì)替換子組件的<slot></slot>標(biāo)簽陷舅。

1倒彰、匿名插槽

匿名插槽,我們又可以叫它單個(gè)插槽或者默認(rèn)插槽莱睁。與具名插槽相對(duì)待讳,它不需要設(shè)置name屬性。(它隱藏的name屬性為default仰剿。)
示例:
① 在vue子組件中定義一個(gè)匿名插槽

<script>
        Vue.config.productionTip = false
        Vue.component('b-box', {
            template: `
                <div class="box">
                    <div class="item">
                        <h2>插槽</h2>
                        <slot></slot>
                    </div>
                </div>
            `
        })
        new Vue({
            el: '#app',
        })
    </script>

② 在頁(yè)面中使用子組件標(biāo)簽创淡,并寫(xiě)入內(nèi)容

<div id="app">
        <b-box>
            <!-- 如果沒(méi)有slot插槽,這里的內(nèi)容將不會(huì)顯示 -->
            <div>我是匿名插槽</div>
        </b-box>
    </div>

效果如圖:


image.png

2酥馍、具名插槽

插槽有一個(gè)特殊的屬性:name辩昆,這個(gè)屬性可以用來(lái)定義多個(gè)插槽。
在向具名插槽提供內(nèi)容的時(shí)候旨袒,我們可以在一個(gè) <template> 元素上使用 v-slot 指令汁针,并以 v-slot 的參數(shù)的形式提供其名稱(chēng)术辐。
v-slot:的簡(jiǎn)寫(xiě)為#
使用方法如下:

<div id="app">
        <b-box>
            <template v-slot:slot1>
                <div>我是插槽1</div>
            </template>
            <template v-slot:slot2>
                <div>我是插槽2</div>
            </template>
            <template v-slot:slot3>
                <div>我是插槽3</div>
            </template>
        </b-box>
    </div>
<script>
       Vue.config.productionTip = false
       Vue.component('b-box', {
           template: `
               <div class="box">
                   <div class="item">
                       <h2>插槽1</h2>
                       <slot name="slot1"></slot>
                   </div>
                   <div class="item">
                       <h2>插槽2</h2>
                       <slot name="slot2"></slot>
                   </div>
                   <div class="item">
                       <h2>插槽3</h2>
                       <slot name="slot3"></slot>
                   </div>
                   
               </div>
           `
       })
       new Vue({
           el: '#app',
       })
   </script>

實(shí)現(xiàn)效果如下:
image.png

3、作用域插槽

作用域插槽其實(shí)就是可以傳遞數(shù)據(jù)的插槽施无。子組件中的一些數(shù)據(jù)想在父組件中使用辉词,必須通過(guò)規(guī)定的方法來(lái)傳遞。
作用域插槽必須是具名插槽,在作用域插槽上可以通過(guò)v-bind:綁定屬性猾骡,綁定的屬性瑞躺,通過(guò)指定的作用域變量是接收 。

綁定在元素上的 屬性被稱(chēng)為插槽 prop⌒讼耄現(xiàn)在在父級(jí)作用域中幢哨,我們可以使用帶值的 v-slot 來(lái)定義我們提供的插槽 prop 的名字:

//default可以省略,簡(jiǎn)寫(xiě)為v-slot=" "嫂便,slotProps是自定義的名字捞镰,
 <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

具體使用如下:

<div id="app">
        <!-- 作用域插槽必須是具名插槽,在作用域插槽上可以通過(guò)v-bind:綁定屬性,綁定的屬性毙替,通過(guò)指定的作用域變量是接收 -->
        <b-box>
            <template #list="scope">
                <button @click="priceDown(scope.list,scope.index)">降價(jià)</button>
                <button @click="priceUp(scope.list,scope.index)">加價(jià)</button>
                <button @click="scope.list.splice(scope.index,1)">刪除</button>
            </template>
        </b-box>
    </div>
<script>
        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: '蘋(píng)果手機(jī)',
                            price: 6799
                        },
                        {
                            id: 1002,
                            name: '華為手機(jī)',
                            price: 5999
                        },
                        {
                            id: 1003,
                            name: '小米手機(jī)',
                            price: 1799
                        },
                        {
                            id: 1004,
                            name: '紅米手機(jī)',
                            price: 3499
                        },
                    ]
                }
            },
        })
        new Vue({
            el: '#app',
            methods: {
                priceDown(list,index){
                    list[index].price-=1000
                },
                priceUp(list,index){
                    list[index].price+=1000
                },
            },
        })
    </script>

四岸售、混入

混入 (mixin) 提供了一種非常靈活的方式,來(lái)分發(fā) Vue 組件中的可復(fù)用功能厂画。一個(gè)混入對(duì)象可以包含任意組件選項(xiàng)凸丸。當(dāng)組件使用混入對(duì)象時(shí),所有混入對(duì)象的選項(xiàng)將被“混合”進(jìn)入該組件本身的選項(xiàng)袱院。

1屎慢、選項(xiàng)合并

當(dāng)組件和混入對(duì)象含有同名選項(xiàng)時(shí),這些選項(xiàng)將以恰當(dāng)?shù)姆绞竭M(jìn)行“合并”坑填。
比如抛人,數(shù)據(jù)對(duì)象在內(nèi)部會(huì)進(jìn)行遞歸合并,并在發(fā)生沖突時(shí)以組件數(shù)據(jù)優(yōu)先脐瑰。

var mixin = {
  data: function () {
    return {
      message: 'hello',
      foo: 'abc'
    }
  }
}

new Vue({
  mixins: [mixin],
  data: function () {
    return {
      message: 'goodbye',
      bar: 'def'
    }
  },
  created: function () {
    console.log(this.$data)
    // => { message: "goodbye", foo: "abc", bar: "def" }
  }
})

同名鉤子函數(shù)將合并為一個(gè)數(shù)組妖枚,因此都將被調(diào)用。另外苍在,混入對(duì)象的鉤子將在組件自身鉤子之前調(diào)用绝页。

var mixin = {
  created: function () {
    console.log('混入對(duì)象的鉤子被調(diào)用')
  }
}

new Vue({
  mixins: [mixin],
  created: function () {
    console.log('組件鉤子被調(diào)用')
  }
})

// => "混入對(duì)象的鉤子被調(diào)用"
// => "組件鉤子被調(diào)用"

值為對(duì)象的選項(xiàng),例如 methods寂恬、components 和 directives续誉,將被合并為同一個(gè)對(duì)象。兩個(gè)對(duì)象鍵名沖突時(shí)初肉,取組件對(duì)象的鍵值對(duì)酷鸦。

var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}

var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    conflicting: function () {
      console.log('from self')
    }
  }
})

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

注意:Vue.extend() 也使用同樣的策略進(jìn)行合并

2、全局混入

當(dāng)我們存在多個(gè)組件中的數(shù)據(jù)或者功能很相近時(shí),我們就可以利用mixins將公共部分提取出來(lái)臼隔,在 mixin函數(shù)中混入統(tǒng)一的成員嘹裂。

注意:請(qǐng)謹(jǐn)慎使用全局混入,因?yàn)樗鼤?huì)影響每個(gè)單獨(dú)創(chuàng)建的 Vue 實(shí)例 (包括第三方組件)摔握。大多數(shù)情況下寄狼,只應(yīng)當(dāng)應(yīng)用于自定義選項(xiàng)。推薦將其作為插件發(fā)布氨淌,以避免重復(fù)應(yīng)用混入泊愧。

 <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>
        <p>汽車(chē)信息:{{car}}</p>
        <button @click="sayHi">sayHi</button>
        <button @click="getSubjects">請(qǐng)求課程數(shù)據(jù)</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>
<script>
        Vue.config.productionTip = false
        // 給所有的vue實(shí)例混入統(tǒng)一的成員
        Vue.mixin({
            data() {
                return {
                    name:'',
                    age:0,
                    sex:'男',
                    salary:1000
                }
            },
            methods: {
                sayHi(){
                    alert(`大家好!我叫${this.name},性別是${this.sex}盛正,今年${this.age}歲`)
                },
                async $get(url,params){
                    let {data} = await axios.get(url,{params})
                    return data
                },
                async $post(url,params){
                    let {data} = await axios.post(url,params)
                    return data
                }
            },
            computed:{
                salary2(){
                    return this.salary*0.8
                }
            },
            watch:{
                age(val){
                    if (this.age>100) {
                        alert('年齡不能超過(guò)100')
                        this.age = 100
                    }
                }
            },
            mounted() {
                console.log('mixin:掛載完成')
            },
        })

        new Vue({
            el:'#app1',
            data:{
                car:{
                    name:'奔馳',
                    price:'100W'
                },
                subjects:[]
            },
            methods: {
                async getSubjects(){
                    let {data} = await this.$get('http://bingjs.com:81/Subject/GetSubjectsConditionPages',)
                    this.subjects = data
                }
            },
            mounted() {
                console.log('app1:掛載完成')
            },
        })
        new Vue({
            el:'#app2',
            mounted() {
                console.log('app2:掛載完成')
            },
        })
    </script>

效果如圖:


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末删咱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛮艰,更是在濱河造成了極大的恐慌腋腮,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壤蚜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡徊哑,警方通過(guò)查閱死者的電腦和手機(jī)袜刷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)莺丑,“玉大人著蟹,你說(shuō)我怎么就攤上這事∩颐В” “怎么了萧豆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)昏名。 經(jīng)常有香客問(wèn)我涮雷,道長(zhǎng),這世上最難降的妖魔是什么轻局? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任洪鸭,我火速辦了婚禮,結(jié)果婚禮上仑扑,老公的妹妹穿的比我還像新娘览爵。我一直安慰自己,他們只是感情好镇饮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蜓竹。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俱济。 梳的紋絲不亂的頭發(fā)上司蔬,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音姨蝴,去河邊找鬼俊啼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛左医,可吹牛的內(nèi)容都是我干的授帕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浮梢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼跛十!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起秕硝,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤牙言,失蹤者是張志新(化名)和其女友劉穎罐农,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硝拧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了独撇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攀痊。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖棺滞,靈堂內(nèi)的尸體忽然破棺而出裁蚁,到底是詐尸還是另有隱情,我是刑警寧澤继准,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布枉证,位于F島的核電站,受9級(jí)特大地震影響移必,放射性物質(zhì)發(fā)生泄漏室谚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一避凝、第九天 我趴在偏房一處隱蔽的房頂上張望舞萄。 院中可真熱鬧,春花似錦管削、人聲如沸倒脓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)崎弃。三九已至甘晤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饲做,已是汗流浹背线婚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盆均,地道東北人塞弊。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泪姨,于是被迫代替她去往敵國(guó)和親游沿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容