天天看點

從零開始學Vue——模闆文法

title: vue-模闆文法

date: 2020-09-16 21:27:17

tags: Vue

categories: 前端

githubBlog:Click Me

1.Vue模闆文法

1.1插值操作

mustache文法{{expr}}

expr可以是變量,常量,表達式,會自動根據Vue中的data進行渲染

<div id="app">
    <h2>{{message}}</h2>
    <h2>{{message+message}}</h2>
    <h2>{{v*2}}</h2>
    <h2>{{firstName+" "+lastName}}</h2>
    <h2>{{firstName}}{{lastName}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: "test",
            firstName: "hello",
            lastName: "world",
            v: 100
        }
    })
</script>
           

v-once

此時,資料隻從vue中得到資料初始化渲染一次,之後該元件(标簽内)的資料不會随着data中的資料變化

<!--v-once作用域是整個标簽-->
<div id="app">
    <h2  v-once>{{message}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            message: "test",
        }
    })
</script>
           

v-html

類似于innerHtml(),把資料進行解析後顯示

v-text

類似于innerText(),把原資料顯示出來

v-pre

忽略mustache直接顯示出兩個大括号

v-cloak

在Vue渲染html标簽前,讓被渲染的元素隐藏,不顯示原生的{ {} }等文法

1.2動态綁定屬性

v-bind

為标簽的屬性綁定Vue的data值,綁定後屬性值将根據這個data動态改變

v-bind可用冒号

:

代替

<div id="app">
    <!-- 綁定屬性的操作 -->
    <img v-bind:src="imgurl" alt="">
    <a :href="url">百度一下</a>
</div>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            imgurl: 'https://www.baidu.com/img/flexible/logo/pc/result.png',
            url: 'www.baidu.com'
        }
    })
</script>
           

動态參數

https://cn.vuejs.org/v2/guide/syntax.html#%E5%8A%A8%E6%80%81%E5%8F%82%E6%95%B0

v-bind綁定class

通過對象綁定

<h2 :class={ 類名1:boolean,類名2:boolean}>vue</h2>
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>

<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            isActive: true,
            isLine: false
        }
    })
</script>
           
通過一個對象的形式,若類名對應的值(vue中的data)為true值會為标簽綁定class,false則不會,可與原生的class共存。若對象過于複雜,可通過methods或計算屬性傳回一個對象。

通過數組綁定

<h2 class="title" :class="[類名, 類名,···]">Hello World</h2>
<h2 class="title" :class="[active, line]">Hello World</h2>
           
類名可以是一個變量,常量,表達式,最終代表需要綁定的類名

v-bind綁定style

利用v-bind:style來綁定一些CSS内聯樣式。

通過對象綁定

<h1 :style="{屬性名:屬性值,屬性名:屬性值,···}">{{massage}}</h1>

<h1 :style="{color:colorStyle,'background-color':bkColorStyle,fontSize:fSize+'px'}">{{massage}}</h1>
           

屬性名可以是小駝峰式,或者短橫線分隔式(需單引号括起)

屬性值可以是常量,變量,表達式

通過數組綁定

<div v-bind:style="[baseStyles, overridingStyles]"></div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            //可以是駝峰式也可以短橫線分隔式
            baseStyles: {color:'red','background-color':'gray'},
            overridingStyles: {fontSize:'20px'}
        }
    })
</script>
           
數組中放的是對象,每個對象代表一個css樣式,本質上就是通過對象綁定

1.3方法與計算屬性

**方法(methods):**類似于函數,隻不過它屬于指定的vue對象

**計算屬性(computed):**本質上是屬性,隻是多了getter和setter方法(類似于bean),并且與方法methods相比,具備緩存功能,可以動态監聽,當資料改變時才會調用getter

<div id="app">
    <h2>{{fullName}}</h2>
    <h2>{{fullName2}}</h2>
    <!--方法調用必須加上括号(在事件監聽時不用)-->
    <h2>{{fullName3()} }</h2>
    <h2>{{fullName4()} }</h2>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            firstName:'Alan',
            lastName:'Turing'
        },
        computed:{
            fullName: {
                // getter
                get: function () {
                    return this.firstName + ' ' + this.lastName
                },
                // setter
                // 當執行vm.fullName = 'John Doe'會被調用
                set: function (newValue) {
                    let names = newValue.split(' ')
                    this.firstName = names[0]
                    this.lastName = names[names.length - 1]
                }
            },
            //當沒有set方法時,可簡化為如下,并且可省略  :function
            fullName2:function() {
                return (this.firstName+' '+this.lastName).toUpperCase();
            }
        },
        methods:{
            fullName3:function(){
                return this.firstName+' '+this.lastName;
            },
            //可省略  :function
            fullName4(){
                return this.firstName+' '+this.lastName;
            }
        }
    })
</script>
           

1.4偵聽器和濾波器

偵聽器:偵聽vue執行個體中的資料變化,一旦資料發生變化就會執行回調函數

<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val=100;
        }
        watch:{
        //如果data中的val發生改變,就會執行下方函數
        val:function(newVal,oldVal){
            console.log(newVal+' '+oldVal);
        }
    })
</script>
           

濾波器:在輸出内容時,給内容添加修飾。

<div id="app">
    <!-- 最終顯示 ¥100.00 -->
    <span>總價:{{totalPrice |showPrice } }</span>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            totalPrice=100;
        }
        filters:{
        showPrice(totalPrice){
            return "¥"+totalPrice.toFixed(2);
        }
    })
</script>
           

1.5事件監聽

v-on

  • 作用:綁定事件監聽器
  • 縮寫:@
  • 預期:Function | Inline Statement | Object
  • 參數:event

v-on:click="func1"

,引号内填寫函數名,不帶括号時,預設傳入一個event,帶括号時按正常情況傳遞參數,當需要傳遞事件對象時,參數為$event
<div id="app">
    <!-- 點選後會輸出mouseEvent-->
    <button v-on:click="func1">按鈕1</button>
    <!-- 點選後會輸出123 abc-->
    <button @click="func2('123','abc')">按鈕2</button>
    <!-- 點選後會輸出mouseEvent undefine-->
    <button @click="func2">按鈕3</button>
    <!-- 點選後會輸出123 mouseEvent-->
    <button @click="func2('123',$event)">按鈕4</button>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        methods:{
            func1(param1){
                alert("This is btn1:"+param1) ;
            },
            func2(param1,param2){
                alert("This is btn2:"+param1+' '+param2) ;
            }
        }
    })
</script>
           

v-on修飾符

  • .stop - 調用 event.stopPropagation()。
  • .prevent - 調用 event.preventDefault()。
  • .{keyCode | keyAlias} - 隻當事件是從特定鍵觸發時才觸發回調。
  • .native - 監聽元件根元素的原生事件。
  • .once - 隻觸發一次回調。
<!-- 阻止事件冒泡 -->
    <button @click.stop="doThis">button</button>
    <!-- 阻止預設行為發生,可省略doThis -->
    <form @submit.prevent="doThis" action="url">
        <input type="text">
        <input type="submit">
    </form>
    <!-- 串聯修飾符 -->
    <button @click.stop.prevent="doThis">button</button>
    <!-- 鍵修飾符,指定别名或鍵代碼 -->
    <input type="text"  @keyup.enter="doThis" @keydown.10="doThis" >
    <!-- 觸發一次回調 -->
    <button @click.once="doThis">button</button>
           
關于修飾符的知識還很欠缺,例如不同修飾符順序引發不同的結果

一些鍵修飾别名:

  • .enter

  • .tab

  • .delete

    (捕獲 “删除” 和 “倒退” 鍵)
  • .esc

  • .space

  • .up

  • .down

  • .left

  • .right

  • .ctrl

  • .alt

  • .shift

  • .meta

1.6條件渲染

if、else if、else

這三個指令類似于if、else、else if。Vue的條件指令可以根據表達式的值在DOM中渲染或銷毀元素或元件。

<div id="app">
    <h3 v-if="score>=90">Excellent</h3>
    <h3 v-else-if="score>=80">Good</h3>
    <h3 v-else-if="score>=60">Ok</h3>
    <h3 v-else>Fail</h3>
</div>

<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            score:90,
        }
    })
</script>
           

v-show

v-show

v-if

的用法類似,都是決定一個頁面是否被渲染。

差別:

v-if

當條件為false時,壓根不會有對應的元素在DOM中。

v-show

當條件為false時,僅僅是将元素的

display

屬性設定為

none

而已。

當需要在顯示與隐藏之間切片很頻繁時,使用`v-show`。

	當隻有一次切換時,通過使用`v-if`。
           

1.7清單渲染

v-for

<!--周遊數組-->
<li v-for="value in arr">{{value}}</li>
<li v-for="(value,index) in arr">{{value}}-{{index}}</li>

<!--周遊對象-->
<li v-for="value in obj">{{value}}</li>
<li v-for="(value,key) in obj">{{value}}-{{key}}</li>
<li v-for="(value,key,index) in obj">{{value}}-{{key}}-{{index}}</li>
           

數組響應式更新

Vue具有資料綁定的功能,是以當vue執行個體中的資料發生改變時,視圖能做出改變響應。

對數組使用如下方法,都會使得視圖發生更新

//函數的具體用法有待了解
let arr;
arr.push();
arr.pop();
arr.unshift();
arr.shift();
arr.splice();
arr.sort();
arr.reverse();
           

唯一需要注意的是使用如下方式1的數組下标指派的方法,視圖并不會發生更新

//方式1
let arr=[{key:value}];
arr[0]={key2:value2};	//視圖并不更新
//方式2
let arr2={key:value};
arr2[0].key=value2;	//本質上是修改對象的的屬性内容,視圖發生更新

//解決方式1視圖不更新的兩種方式
//通過splice方法為數組指派,具體用法有待了解
//通過vue自帶的方法為數組指派
Vue.set(this.arr,index,value);
           

1.8兩個練手小案例:

點選綁定樣式和購物車

1.9v-model表單綁定

你可以用

v-model

指令在表單

<input>

<textarea>

<select>

元素上建立雙向資料綁定。它會根據控件類型自動選取正确的方法來更新元素。此外input中的value屬性也支援v-bind動态綁定。

v-model原理

v-model其實是一個文法糖,它負責監聽使用者的輸入事件以更新資料,并對一些極端場景進行一些特殊處理。它的背後本質上是包含兩個操作:

  • 1.v-bind綁定一個value屬性
  • 2.v-on指令給目前元素綁定input事件

v-model

會忽略所有表單元素的

value

checked

selected

attribute 的初始值而總是将 Vue 執行個體的資料作為資料來源。你應該通過 JavaScript 在元件的

data

選項中聲明初始值。

v-model

在内部為不同的輸入元素使用不同的 property 并抛出不同的事件:
  • text 和 textarea 元素使用

    value

    property 和

    input

    事件;
  • checkbox 和 radio 使用

    checked

    property 和

    change

    事件;
  • select 字段将

    value

    作為 prop 并将

    change

    作為事件。

以下代碼等價:

文本

<div id="app">
    
    <p>單行文本:Message is: { { message1 } }</p>
    <input v-model="message1" placeholder="edit me">
    <br>
    <hr>
    <span>多行文本: Multiline message is:</span>
    <p style="white-space: pre-line;">{{ message2 } }</p>
    <br>
    <textarea v-model="message2" placeholder="add multiple lines"></textarea>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            message1:'' ,
            message2:''
        }
    })
</script>
           

單選按鈕

<div id="app">
    <input type="radio" id="one" value="One" v-model="picked">
    <label for="one">One</label>
    <br>
    <input type="radio" id="two" value="Two" v-model="picked">
    <label for="two">Two</label>
    <br>
    <span>Picked: { { picked } }</span>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            picked: '',
        }
    })
</script>
           
原生的單選按鈕中,不同的按鈕需要通過一個相同的name來實作互斥,當使用v-model時,可通過綁定同一個value來實作互斥。

複選框

<h3>單個複選框</h3>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked } }</label>

<h3>多個複選框</h3>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: { { checkedNames } }</span>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            checked:undefined,//初始化時給一個true則預設會被選中,false或其它非布爾值預設不選
            checkedNames: [],
        }
    })
</script>

           

選擇框

<h3>單個選擇框</h3>
    <div>
        <select v-model="option">
            <option disabled value="">請選擇</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <span>Selected: { { option } }</span>
    </div>
    <h3>多個選擇框</h3>
    <div>
        <select v-model="options" multiple style="width: 50px;">
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <br>
        <span>Selected: { { options } }</span>
    </div>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            option:'',
            options: [],
        }
    })
</script>
           

修飾符

lazy修飾符:
  • 預設情況下,v-model預設是在input事件中同步輸入框的資料的。
  • 也就是說,一旦有資料發生改變對應的data中的資料就會自動發生改變。
  • lazy修飾符可以讓資料在失去焦點或者回車時才會更新:
number修飾符:
  • 預設情況下,如果希望使用者輸入數字,原生的input提供了type="number"的用法,但是在輸入框中無論我們輸入的是字母還是數字,都會被當做字元串類型進行處理。
  • 是以可通過

    <input v-model.number="age" type="number">

  • v-model

    添加

    number

    修飾符可以讓在輸入框中輸入的内容自動轉成數字類型:
trim修飾符:
  • 如果要自動過濾使用者輸入的首尾空白字元,可以給

    v-model

    添加

    trim

    修飾符:

    <input v-model.trim="msg">

2.元件化開發

元件是可複用的 Vue 執行個體,且帶有一個名字,并且元件相對于Vue來說多了一些例如template模闆等功能,template使得元件内部可封裝某些标簽資料。

2.1.元件使用流程

基本使用

  1. 建立元件對象(最新vue手冊中已不使用Vue.extend()建立元件對象了)
  2. 調用Vue.component()方法注冊元件
  3. 在Vue執行個體的作用範圍内使用元件
<div id="app">
    <!-- 3.在Vue執行個體挂載的标簽範圍内使用元件-->
    <cpn></cpn><!-- 此标簽最終會由cpnObj中的template進行渲染-->
</div>
<cpn></cpn>
<script>
    //1.建立元件對象
    //注意template最終必須由一個根标簽包含,例如下方根标簽為div
    //其中template代表該元件對象的模闆,該對象還可有data,methods等屬性
    //這是使用Vue.extend方式(過時)
    //通過構造器建立元件對象
	// const cpnObj = Vue.extend({
    //     template:`
    //             <div>
    //                 <h3>我是标題</h3>
    //                 <div>我是内容</div>
    //             </div>
    //     `
    // });
    
    //直接使用javascript對象
    const cpnObj = {
        template:`
                <div>
                    <h3>我是标題</h3>
                    <div>我是内容</div>
                </div>
        `
    };
    //2.将元件對象注冊為元件(元件标簽,元件對象)
    Vue.component('cpn',cpnObj);
    const vm = new Vue({
        el: '#app',
    });
</script>
           

文法糖

直接在注冊時傳入對象參數

<script>
    //将定義元件對象,并注冊為元件(元件标簽,元件對象)
    Vue.component('cpn',{
        template:`
                <div>
                    <h3>我是标題</h3>
                    <div>我是内容</div>
                </div>
        `
    });
</script>
           

2.2全局元件和局部元件

全局元件:

凡是以Vue.component()進行注冊的都是全局元件,可以在任何挂載了Vue執行個體的标簽内使用

局部元件:

在Vue執行個體中注冊,或在元件中注冊為子元件的元件都是局部元件,他們的作用範圍限于各自注冊的執行個體(元件)中。

一個元件對象可在不同的作用域中注冊為不同的元件

代碼執行個體:

<div id="app">
    <cpn2></cpn2>
    <cpn1></cpn1>
</div>
<script>
    //這是子元件對象,可(同時)在vue執行個體(或元件)中注冊
    const cpnObj1 = {
        template:`
                <div>
                   <h3>标題1</h3>
                </div>
        `
    };
    //第一種:注冊成為子元件:
    //1.構造元件2對象時,把元件對象cpnObj1代表的元件添加為元件2的子元件
    const cpnObj2 = {
        template:`
            <div style="color: #ff0000">
                <h3>标題2</h3>
                <cpn1></cpn1>
            </div>
        `,
        components:{
            //元件标簽名:元件對象
            cpn1:cpnObj1    //作用域僅在該元件中,(可用文法糖)
        }
    };
    //2.将元件2對象注冊為元件(元件标簽,元件對象)
    Vue.component('cpn2',cpnObj2);  //全局元件:作用域在任何Vue執行個體中
	
    //第二種:在Vue執行個體中注冊
    const vm = new Vue({
        el: '#app',
        components:{
            //元件标簽名:元件對象
            cpn1:cpnObj1 //作用域僅在該Vue執行個體中(可用文法糖)
        }
    })
</script>
           

2.3分離模闆

可将元件的template分離出來,單獨寫在一個标簽中

使用script标簽

使用script标簽包裹template,并給定id,然後在元件對象中引用template的id即可
<script type="text/x-template" id="myCpn">
    <div>
        <h3>這是元件</h3>
    </div>
</script>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
    const cpnObj = Vue.extend()

    const vm = new Vue({
        el: '#app',
        components:{
            cpn: {
              template:'#myCpn'	//引用script中的id
            }
        }
    })
</script>
           

使用template标簽

與script标簽相比,不用指定type=“text/x-template”,其餘相同
<template id="myCpn">
    <div>
        <h3>這是元件</h3>
    </div>
</template>
<script>
    const cpnObj = Vue.extend()

    const vm = new Vue({
        el: '#app',
        components:{
            cpn: {
              template:'#myCpn'
            }
        }
    })
</script>
           

2.4元件data

問題引入:元件也是一個Vue執行個體,意味着元件也可以有自己的data,那麼當元件标簽使用多次時,每個元件标簽引用的是同一個data,這樣是明顯不合理的,即在元件複用的時候,它們應該引用不同的data對象。
解決方法:Vue強制規定在元件中必須把data寫成函數的形式,并且該函數傳回一個對象來作為該元件的data,利用函數的作用域來讓每個元件标簽引用不同的資料對象。
每一次使用元件,function中都會有一個對象被建立并指派給data

code

<div id="app">
    <cpn></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>這是元件:{{msg}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        components:{
            cpn:{
                //此處的元件對象中的data使用的是函數
                data(){
                    return {
                        msg:'message'
                    }
                },
                template: '#myCpn'
            }
        }
    })
</script>
           

2.5父子元件的資料傳遞

子元件是無法通路父元件或Vue執行個體中的資料的,而在實際的開發中,常常需要把父元件的資料傳遞給子元件使用,是以Vue提供了父子元件間傳遞資料的方法。

值得注意的是:當一個元件1在某個元件2内部注冊為局部元件後不代表該元件1就是元件2的子元件了,隻能說明元件1是作用在元件2内部的局部元件。

判斷是否為一個元件的子元件看的是在template标簽中是否嵌套使用了元件标簽,例如在挂載了vue執行個體的div中使用元件标簽cpn,此時cpn就是vue的子元件

父元件=>子元件 props

父元件(Vue執行個體)把資料傳遞給子元件中的props屬性。

  1. 在子元件中的props中聲明自己的屬性(prop),用于接收父元件傳遞的資料
  2. 在使用該子元件标簽時,為該子元件的prop屬性指派或動态綁定變量
<div id="app">
    <!-- 在使用元件時給attr1 prop指派-->
    1:<cpn attr1="attribute1"></cpn>
    <!-- 在使用元件時給attr2 prop動态綁定為vue執行個體中的val-->
    2:<cpn :attr2="val"></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>這是屬性1:{{attr1}}</h3>
        <h3>這是屬性2:{{attr2}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'attribute2'
        },
        components:{
            cpn:{
                template: '#myCpn',
                //聲明屬性,有數組和對象兩種形式,此處是數組
                props:['attr1','attr2'] //屬性以字元串形式書寫
            }
        }
    });
</script>
           
當需要對傳入子元件中的prop進行類型驗證或預設值等操作時,就需要采用對象文法,執行個體如下
<div id="app">
    <!-- 在使用元件時給attr1 prop指派,類型必須是Number是以必須動态綁定-->
    1:<cpn :attr1="num"></cpn>
    <!-- 在使用元件時給attr2 prop動态綁定為vue執行個體中的val-->
    2:<cpn :attr2="val"></cpn>
</div>
<template id="myCpn">
    <div>
        <h3>這是屬性1:{{attr1}}</h3>
        <h3>這是屬性2:{{attr2}}</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'DeliveredParameter',
            num:10
        },
        components:{
            cpn:{
                template: '#myCpn',
                //聲明屬性:對象形式
                props:{
                    attr1:{
                        type: Number,
                        //表示這個屬性attr1在使用元件時必須傳遞參數
                        //required: true	
                    },
                    attr2:{
                        type: String,
                        default(){  //此處因該使用函數
                            return 'DefaultString';
                        }
                    }
                }
            }
        }
    });
</script>
           
支援的資料驗證類型:驗證都支援哪些資料類型呢?String,Number,Boolean,Array,Object,Date,Function,Symbol

子元件=>父元件 $emit

子元件通過觸發自定義事件傳遞資料

父元件(Vue執行個體)則通過v-on監聽子元件觸發的事件,并從參數中獲得資料。

<div id="app">
    <!--此處的自定義事件出來函數不應該加括号,vue會自動傳遞參數,隻需在method中接收即可-->
    <cpn @my-event="handler"></cpn>
</div>
<template id="myCpn">
    <div>
        <!--此處是普通的v-on-->
        <button @click="BtnClick()">Click me!</button>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'DeliveredParameter',
        },
        methods:{
            handler(val){
                console.log('handler is done:'+val);
          }
        },
        components:{
            cpn:{
                template: '#myCpn',
                //聲明屬性:對象形式
                props:{
                    attr:{
                        type: String,
                        default(){  //此處因該使用函數
                            return 'DefaultString';
                        }
                    }
                },
                methods:{
                    BtnClick(){
                        //子元件通過$emit觸發自定義事件myEvent,并傳遞參數attr
                        this.$emit('my-event',this.attr);
                    }
                }
            }
        }
    });
</script>
           

2.6父子元件的互相通路

有時候,在父元件内可能會出現引用子元件中某個函數或變量的情況,vue提供了三個變量來實作父子元件間的互相通路。

父元件通路子元件: c h i l d r e n 或 children或 children或refs

子元件通路父元件:$parent

子元件通路根元件:$root

代碼示例:

<div id="app">
    <cpn></cpn>
    <cpn></cpn>
</div>
<template id="tem1">
    <div>
        <h3>I am son</h3>
        <ccpn></ccpn>
        <ccpn></ccpn>
    </div>
</template>
<template id="tem2">
    <div>
        <h3>I am grandson</h3>
    </div>
</template>
<script>
    const vm = new Vue({
        el: '#app',
        data:{
            val:'I am root',
        },
        methods:{
            func1(){
                //this.$children代表目前元件(Vue執行個體)下的所有子元件(Vue component)
                console.log(this.$children[0].val);
          }
        },
        components:{
            cpn:{
                template: '#tem1',
                data(){
                  return{
                      val: 'I am son'
                  }
                },
                methods:{
                    func1(){
                        //this.$parent代表目前元件的父元件Vue
                        console.log(this.$parent.val);
                    }
                },
                //聲明屬性:對象形式
                components: {
                    ccpn:{
                        template: '#tem2',
                        data() {
                            return {
                                val: 'I am grandson'
                            }
                        },
                        methods:{
                            func1(){
                                //this.$root代表目前元件的根元件Vue執行個體
                                console.log(this.$root.val);
                            }
                        }
                    },
                }
            },
        }
    });
</script>
           

采用$children形式得到的是包含所有子元件的數組,并且索引與順序有關

由于元件标簽中同一級别的标簽數量和标簽可能發生變化,是以這種方法顯然在修改時不太容易。

r e f s 就 可 避 免 這 個 問 題 t h i s . refs就可避免這個問題this. refs就可避免這個問題this.refs得到的是一個包含所有子元件的對象, r e f s 使 用 時 隻 需 要 為 每 個 子 組 件 指 定 一 個 鍵 , r e f = " i d " , 然 後 父 組 件 再 引 用 時 采 用 t h i s . refs使用時隻需要為每個子元件指定一個鍵,ref="id",然後父元件再引用時采用this. refs使用時隻需要為每個子元件指定一個鍵,ref="id",然後父元件再引用時采用this.refs.id即可通路子元件

<div id="app">
 <cpn ref="first"></cpn>
 <cpn ref="second"></cpn>
</div>
<script>
	const vm = new Vue({
     el: '#app',
     data: {
         val: 'I am root',
     },
     methods: {
         func1() {
             console.log(this.$refs.first);
         }
     },
 }
</script>
           

2.7slot插槽

基本插槽

在編寫元件模闆的時候,會出現兩個模闆高度相似的情況,為了更好的複用模闆,vue提出了在元件模闆中引入插槽slot。slot标簽内表示預留一個位置可供其它html代碼或元件插入。提高了元件的複用性和可擴充性。

<div id="app">
    <cpn></cpn><!-- 插槽内容為預設的button -->
    <cpn><span>自定義内容1</span></cpn><!-- 插槽内容為自定義span -->
</div>

<template id="tem1">
    <div>
        <h3>我是元件</h3>
        <!-- slot标簽内容為空,表示不提供預設内容 -->
        <slot><button>預設内容</button></slot>
    </div>
</template>
           

若元件cpn的template

中沒有包含一個

<slot>

元素,則該元件起始标簽和結束标簽之間的任何内容都會被抛棄(即cpn标簽内部内容無效)。

該插槽跟模闆的其它地方一樣可以通路相同的執行個體 property (也和vue元件擁有相同的“作用域”)

具名插槽

當一個模闆中需要有多個插槽的時候,如果在使用的時候vue預設把cpn标簽的内容區替換每個v-slot标簽,這個時候就需要為每個插槽指定名稱,并在使用時注明。

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <!-- 一個不帶name的<slot>出口會帶有隐含的名字“default”-->
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
           
在向具名插槽提供内容的時候,我們可以在一個

<template>

元素上使用

v-slot

指令,并以

v-slot

的參數的形式提供其名稱:v-slot可縮寫為#,使用縮寫時必須帶上插槽名,例如default
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
  <!-- 任何沒有被包裹在帶有 v-slot 的 <template> 中的内容都會被視為預設插槽的内容。 
	下面的兩個p标簽也可包裹在<template v-slot:default><template>标簽裡
-->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
           

作用域插槽

由于元件的編譯作用域原因,父元件中無法通路子元件的資料,意味着當父元件向子元件中的slot中插入内容時無法通路到子元件中的資料。

為了解決這一問題,vue提供了作用域插槽,即在為每個執行個體slot綁定一個function,在把子元件的資料傳遞到該function的作用域中,實作了每個插槽都有自己單獨的作用域。

本質上是:為每個執行個體的slot标簽提供一個作用域,子元件可把資料綁定到slot作用域裡,然後父元件在往slot中插入東西時,可以通路slot作用域中的資料。

CODE

<div id="app">
    <!--  沒有插入時 插槽顯示預設内容-->
    <cpn></cpn>
    <!--  将template标簽内容作為插槽内容插入 -->
    <cpn>
        <!--  此處為該slot命名一個作用域myScope,并根據作用域名通路v-bind:綁定的val(實際上是user的别名)-->
        <template v-slot:default="myScope"> 
            <span>自定義顯示年齡:{{myScope.val.age}}</span>
        </template>
    </cpn>
</div>

<template id="tem1">
    <div>
        <h3>我是元件</h3>
        <!--  v-bind:此處把子元件data()中的user綁定到slot執行個體作用域,并取名為val-->
        <slot v-bind:val="user"><span>預設顯示子元件data()中的user.name(姓名):{{user.name}}</span></slot>
    </div>
</template>

<script>
    const vm = new Vue({
        el: '#app',
        components:{
            cpn:{
                template: '#tem1',
                data(){
                  return{
                      user: {
                          name:'Qian',
                          age:21,
                      }
                  }
                },
            },
        }
    });
</script>
           

獨占插槽

當被提供的内容隻有預設插槽時,元件的标簽才可以被當作插槽的模闆來使用,不需要被template标簽包裹。這樣我們就可以把

v-slot

直接用在元件上:

<current-user v-slot:default="slotProps"> 
  { { slotProps.user.firstName } }
</current-user>
<!-- 其中的:default可以省略 -->
           
當元件内有多個插槽時,為所有的插槽使用完整的基于

<template>

的文法:即每個插槽内容均包裹于template,且指定v-slot:default(othername)

附(一):參考:

阿清部落格:https://aqingya.cn/articl/92af846d.html

官網文檔:https://cn.vuejs.org/v2/guide/

附(二)快捷鍵:

"string".log +tab = console.log("string")

div#a + tab = <div id="a"></div>
div.b + tab  = <div class="b"></div>
           

繼續閱讀