Vue 教程第六篇—— 元件

DK_Lan發表於2018-04-18

元件

元件(Component)是前端在單頁面應用(SPA)上最好的一種實現方式,把所有功能模組拆解成單獨的元件,每個元件都有獨立的作用域,且還可以相互通訊

認識單頁面應用(SPA)

在傳統的頁面之間跳轉,是通過重新整理,重新渲染一個頁面而實現,在渲染的過程中勢必要載入外部資原始檔,頁面在伺服器中渲染出來是通過一系列的生命週期,在這個過程中會因為網速等硬體問題直接影響頁面的載入速度,為解決這一問題,前端在新的設計模式上引入了元件的概念,頁面之間的跳轉變成了元件之間的切換,不需要重新載入整個頁面,也不用考慮頁面的生命週期,換成元件的生命週期,在效能上大大的提升了。

Vue 的元件實現

全域性元件

    <div id="app">
        <!--元件的使用-->
        <global-component></global-component>
    </div>
    //元件的定義 Vue.component(元件名稱, {template})
    Vue.component(`global-component`, {
        template: `<h1>全域性元件</h1>`
    })

    var vm = new Vue({
        el: `#app`
    })

最終渲染的效果

    <div id="app">
        <h1>全域性元件</h1>
    </div>

區域性元件

    <div id="app">
        <!--元件的使用-->
        <private-component></private-component>
    </div>
    //元件的定義 Vue.component(元件名稱, {template})
    var vm = new Vue({
        el: `#app`,
        components:{
            `private-component`: {
                template: `<h1>區域性元件</h1>`
            }
        }
    })

最終渲染的效果

    <div id="app">
        <h1>區域性元件</h1>
    </div>

元件是一個單獨的作用域

每個元件都有單獨的作用域

    <div id="app">
        <p>{{count}}</p>
        <component1/>
    </div>    
    var vm = new Vue({
        el: `#app`,
        data: {
            count: 10
        },
        methods: {
            increment: function(){
                this.count += 1;
            }
        },
        components:{
            `component1`: {
                template: `<button v-on:click="increment">{{ count }}</button>`,
                data: function(){
                    //在元件裡面 data 一定是 function 並返回一個物件
                    return {
                        count: 0
                    }
                },
                methods: {
                    increment: function(){
                        this.count += 1;
                    }
                }
            }
        }
    })

渲染結果為

    <div id="app">
        <p>10</p>
        <!--
            此按鈕每次點選都會自增 1,而 p 標籤永遠都是為 10
            原因為元件的作用域是單獨的
        -->
        <button>0</button>
    </div>    

效果預覽

特殊的 HTML 結構中使用 is

比如在下拉選單(select)元素裡面,子元素必須為 option,則在使用元件的時候用 is

    <div id="app">
        <select>
            <option is="privateOption"></option>
        </select>
    </div>
    var vm = new Vue({
        el: `#app`,
        components: {
            `privateOption`: {
                template: `<option value=1>1</otpion>`
            }
        }
    })

渲染結果

    <div id="app">
        <select>
            <option value="1">1</option>
        </select>
    </div>

動態元件 – :is

<div id="app" style="display: none;">
    <input type="button" value="changeLight" @click="changeLight" />
    <br/>
    <p :is="show"></p>
</div>

<script type="text/javascript">
    var vm = new Vue({
        el: `#app`,
        data: {
            show: `red`,
        },
        methods:{
            changeLight: function(){
                this.show = this.show == `red` ? `green` : `red`;
            }
        },
        components: {
            red: {
                template: `<h1>Red</h1>`
            },
            green: {
                template: `<h1>Green</h1>`
            }
        }
    })
</script>

元件屬性

元件的屬性要先宣告後使用,props: [`屬性名`…]

    <div id="app">
        <!--元件的使用-->
        <private-component title="元件屬性" :text="mess"></private-component>
    </div>
    //元件的定義 Vue.component(元件名稱, {template})
    var vm = new Vue({
        el: `#app`,
        data: {
            mess: `-動態屬性`
        }
        components:{
            `private-component`: {
                template: `<h1>{{title + text}}</h1>`,
                props: [`title`, `text`]
            }
        }
    })

最終渲染的效果

    <div id="app">
        <h1>元件屬性-動態屬性</h1>
    </div>

元件自定義事件

和元件屬性不一樣的在於 <元件名 v-bind:屬性名=””>,屬性名要在元件中先宣告再使用:props: [`屬性名`]
自定義事件:<元件名 v-on:自定義事件名=””>,自定義事件名不需要宣告,直接用 $emit() 觸發

    <div id="app">
        <p>{{total}}</p>
        <increment-total v-on:count="incrementTotal"></increment-total>
    </div>
    var vm = new Vue({
        el: `#app`,
        data: {
            total: 0
        },
        methods: {
            incrementTotal: function(){
                this.total += 1;
            }
        },
        components: {
            `incrementTotal`: {
                template: `<input type="button" @click="incrementTotal" value="Total" />`,
                data: function(){
                    return {
                        total: 0
                    }
                },
                methods: {
                    incrementTotal: function(){
                        this.total += 1;
                        this.$emit(`count`)
                    }
                }
            }
        }
    })

slot 分發內容

Vue 元件預設是覆蓋渲染,為了解決這一問題,Vue 提出了 slot 分發內容

    <div id="app">
        <component1>
            <h1>Sam</h1>
            <h1>Lucy</h1>
        </component1>
    </div>
    Vue.component(`component1`, {
        template: `
            <div>
                <h1>Tom</h1>
                <slot></slot>
            </div>
        `
    })

最終渲染的效果

    <div id="app">
        <component1>
            <h1>Tom</h1>
            <!--
                如果在元件定義的 template 當中沒有 <slot></slot>,那麼下面兩個 h1 標籤將不會存在
                換句話說就是 <slot></slot> = <h1>Sam</h1><h1>Lucy</h1>
                <slot></slot>可以放到 <h1>Tom</h1> 上面進行位置調換
            -->
            <h1>Sam</h1>
            <h1>Lucy</h1>
        </component1>
    </div>

具名 slot

如果要將元件裡面不同的子元素放到不同的地方,那就為子元素加上一個屬性 slot=”名稱”,然後在元件定義的時候用名稱對應位置 <slot name=”名稱”></slot>,其它沒有 slot 屬性的子元素將統一分發到 <slot></slot> 裡面

    <div id="app">
        <component1>
            <h1>Sam</h1>
            <h1 slot="lucy">Lucy</h1>
        </component1>
    </div>
    Vue.component(`component1`, {
        template: `
            <div>
                <slot name="lucy"></slot>
                <h1>Tom</h1>
                <slot></slot>
            </div>
        `
    })

最終渲染的效果

    <div id="app">
        <component1>
            <!--<slot name="lucy"></slot> = <h1 slot="lucy">Lucy</h1>-->
            <h1>Lucy</h1>
            <h1>Tom</h1>
            <!--其它沒有 slot 屬性的子元素將全部分發到 <slot></slot> 標籤-->
            <h1>Sam</h1>
        </component1>
    </div>

模版寫法

    <template id="component1">
        <div>
            <input type="text" v-model="name"/>
            <p>{{name}}</p>            
        </div>
    </template>

    <div id="app">
        <component1/>
    </div>     
    var vm = new Vue({
        el: `#app`,
        components: {
            `component1`: {
                template: `#component1`,
                data: function(){
                    return {name: `Tom`};
                }
            }
        }
    })

相關文章