1. 程式人生 > 實用技巧 >Vue 之三區域性元件與全域性元件

Vue 之三區域性元件與全域性元件

一:元件化開發基礎

1.元件是什麼?有什麼用?

元件就是:擴充套件 HTML 元素,封裝可重用的程式碼,目的是複用
例如:有一個輪播圖,可以在很多頁面中使用,一個輪播有js,css,html
元件把js,css,html放到一起,有邏輯,有樣式,有html

元件的分類:

  • 全域性元件:可以放在根中
  • 區域性元件:

工程化開發之後:

1個元件 就是1個xx.vue

二:元件的註冊方式

1. 定義全域性元件,繫結事件,編寫樣式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="
UTF-8"> <title>全域性元件</title> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script> </head> <body> <div id="box"> <div @click="handleClick">我是根部元件</div> <global></global> <ul> <li v-for
="i in 4"> <global></global> </li> </ul> </div> </body> <script> // 建立1個元件物件(全域性元件) Vue.component('global', {
                                  // global是元件名
                    // template 是元件的html樣式
                    // methods 是元件的方法

                    // data()函式 是存放元件的變數名,在元件中data函式中的變數名要以retun的方式定義
template: ` <div> <div style="background: rgba(255,104,104,0.7); padding: 5px;" @click="handleClick">我是頭部元件</div> <div v-if="isShow">顯示消失</div> </div> `, 

methods: { handleClick() { console.log(
'我被點選了') this.isShow = !this.isShow } },

data() {
return { isShow: true } } })

let vm
= new Vue({ el: '#box', data: { isShow: true },
methods: { handleClick() { console.log(
'我被點選了 我是根元件') } } }) </script>
</html>

3. 定義區域性元件

① 區域性元件 放在 Vue例項(根元件) 中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>區域性元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box" style="max-width: 300px">
    <local></local>
    <global></global>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
                    我是全域性元件
                </div>
            </div>
        `,
    })
    let vm = new Vue({
        el: '#box',
        data: {},
        // 建立1個元件物件(區域性元件)
        components: {
            local: {    // local 元件名
                template: `
                    <div>
                        <div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;"
                             @click="handleClick">我是區域性元件
                        </div>
                    </div>
                `,  // 元件的模板
                methods: {
                    handleClick() {
                        console.log('我被點選了')
                    }
                }
            }
        }
    })
</script>
</html>

② 區域性元件 放在 全域性元件 中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>區域性元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
    
<div id="box" style="max-width: 300px">
    <ul>
        <li v-for="i in 3">
            <global></global>
        </li>
    </ul>
</div>
    
</body>
<script>
    // 建立1個元件物件(全域性元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
                    我是全域性的元件
                </div>
                <local></local>
                <local></local>
                <br>
            </div>
        `,
        // 建立1個元件物件(區域性元件)
        components: {
            local: {
                template: `
            <div>
                <div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;">我是區域性元件</div>
            </div>
        `,
            }
        }
    })
    let vm = new Vue({
        el: '#box',
    })
</script>
</html>

注意點:

  • 定義的元件(body中的位置)必須要放在Vue例項(這也是一個元件 根元件)中
  • 區域性元件 必須放在 全域性元件/根元件 中,無法單獨使用

二:元件編寫方式 與 Vue例項的區別

Vue例項(其實,它也是1個元件,是1個根元件)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <ul>
        <li>字串:{{name}}</li>
        <li>數值:{{age}}</li>
        <li><button @click="handleClick()">Click Here</button></li>
    </ul>
</div>

</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            name: 'Darker',
            age: 18,
        },
        methods: {
            handleClick() {
                alert('按鈕被點選')
            }
        }
    })
</script>
</html>

元件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>區域性元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
    
<div id="box" style="max-width: 300px">
    <ul>
        <li v-for="i in 3">
            <global></global>
        </li>
    </ul>
</div>
    
</body>
<script>
    // 建立1個元件物件(全域性元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
                    我是全域性元件
                </div>
                <local></local>
                <br>
            </div>
        `,
        // 建立1個元件物件(區域性元件)
        components: {
            local: {
                template: `
            <div>
                <div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;">我是區域性元件</div>
            </div>
        `,
            }
        }
    })
    let vm = new Vue({
        el: '#box',
    })
</script>
</html>

區別:

1.自定義元件需要有1個root element,一般包裹在 1個div

2.父子元件的data是無法共享的

  • 這一點就像Docker的容器一樣,是相互隔離的
  • 就算父子的data中資料相同,擁有相同的方法,也是互不影響的

3.元件可以有data、methods、computed....,但是data必須是一個函式

Vue例項:data是1個鍵值對,用來存放屬性的
var vm = new Vue({
    el: '#box',
    data: {
        isShow: true
    }
})
元件:data是1個函式,需要有返回值(return)
Vue.component('global', {
    template: `
        <div>
            <div style="background: rgba(255,104,104,0.7); padding: 5px;" @click="handleClick">我是頭部元件</div>
            <div v-if="isShow">顯示消失</div>
        </div>
`,
    methods: {
        handleClick() {
            console.log('我被點選了')
            this.isShow = !this.isShow
        }
    },
    data() {
        return {
            isShow: true
        }
    }
})

三:元件通訊

1.父傳子

  • 在全域性元件中自定義屬性:<global :myname="name" :myage="19"></global>
  • 在元件中獲取:{{myname}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!-- myName是自定義屬性 -->
    <global myname="name" myage="18"></global>
    <global :myname="name" :myage="19"></global>
    <global :myname="'Ben'" :myage="20"></global>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件/子元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px;">全域性元件/子元件</div>
                {{myname}}
                {{myage}}
            </div>
        `,
        props: ['myname', 'myage']
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {
            name: 'darker'
        },
    })
</script>
</html>

屬性驗證

  • 限制父傳子的變數型別
props: {
    myname: String,
    isshow: Boolean
}

父傳子時候注意以下區別

<global :myname="name" :myage="19" :isshow="'false'"></global>
<global :myname="name" :myage="19" :isshow="false"></global>
<global :myname="name" :myage="19" :isshow="isshow"></global>

例項

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!-- myName是自定義屬性 -->
    <!--    <global :myname="name" :myage="19" :isshow="'false'"></global>-->
    <global :myname="name" :myage="19" :isshow="false"></global>
    <global :myname="name" :myage="19" :isshow="isshow"></global>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件/子元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px;">全域性元件/子元件</div>
                <button @click="handleClick">點我顯示/隱藏</button>
                {{myname}}
                {{isshow}}
            </div>
        `,
        props: {
            myname: String,
            isshow: Boolean
        }
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {
            name: 'darker',
            isshow: true
        },
    })
</script>
</html>

3.子傳父(控制子元件的顯示和隱藏)

點選子元件,就會觸發父元件的某個函式執行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子傳父</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global @my_event="handleClick($event)"></global>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件/子元件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: rgba(255,104,104,0.7); padding: 5px;">全域性元件/子元件</div>
                <button @click="handleNav">點我</button>
            </div>
        `,
        data() {
            return {
                name: 'Darker'
            }
        },
        methods: {
            handleNav() {
                console.log('我是子元件的函式')
                this.$emit('my_event', 666, 777, this.name)
            }
        }
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {},
        methods: {
            handleClick(a,b,c) {
                console.log('我是父元件的函式')
                console.log(a)
                console.log(b)
                console.log(c)
            }
        }
    })
</script>
</html>

小案例

  • 子元件有1個按鈕和1個輸入框,子元件輸入完內容後,資料在父元件中展示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子傳父 小案例</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global @my_event="handleShow($event)"></global>
    <br>
    <div>父元件接收到的資料:{{name}}</div>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件/子元件)
    Vue.component('global', {
        template: `
            <div>
                <input type="text" v-model="myText">
                <button @click="handleClick">點我傳資料</button>
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick() {
                this.$emit('my_event', this.myText)
            }
        }
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {
            name: ''
        },
        methods: {
            handleShow(a) {
                this.name = a
            }
        }
    })
</script>
</html>

4.ref屬性(也可以實現元件間通訊:子和父都可以實現通訊)

  • ref放在標籤上,拿到的是原生的DOM節點
  • ref放在元件上,拿到的是元件物件
  • 通過這種方式實現子傳父(this.$refs.mychild.text)
  • 通過這種方式實現父傳子(呼叫子元件方法傳引數)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子傳父</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <input type="text" ref="myRef">
    <button @click="handleButton">點我</button>
</div>

</body>
<script>
    // 建立1個元件物件(全域性元件/子元件)
    Vue.component('global', {
        template: `
            <div>
                <input type="text" v-model="myText">
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick() {
                this.$emit('my_event', this.myText)
                this.$emit('my_event', this.innerHTML)
            }
        }
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {
            name: ''
        },
        methods: {
            handleShow(a) {
                this.name = a
            },
            handleButton() {
                console.log(this.$refs)
                console.log(this.$refs.myRef)
                console.log(this.$refs.myRef.value)
            }
        }
    })
</script>
</html>

5.事件匯流排(不同層級的不通元件通訊)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子傳父</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global1></global1>
    <hr>
    <global2></global2>
</div>

</body>
<script>
    // 定義1個時間匯流排
    let bus = new Vue({})

    // 元件1
    Vue.component('global1', {
        template: `
            <div>
                <h3>元件1</h3>
                <input type="text" v-model="myText">
                <button @click="handleClick1">點我傳遞資料到另一個元件</button>
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick1() {
                console.log(this.myText)
                bus.$emit('any', this.myText)  // 通過事件匯流排傳送
            }
        }
    })
    // 元件2
    Vue.component('global2', {
        template: `
            <div>
                <h3>元件2</h3>
                收到的訊息是:{{recvText}}
            </div>
        `,
        data() {
            return {
                recvText: ''
            }
        },
        mounted() { // 元件的掛載(生命週期鉤子函式中的1個),開始監聽時間總線上的:any
            bus.$on('any', (item) => {
                console.log('收到了', item,)
                this.recvText = item
            })
        },
        methods: {}
    })
    // 父元件
    let vm = new Vue({
        el: '#box',
        data: {},
    })
</script>
</html>

四:動態元件

1.基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>動態元件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <ul>
        <li>
            <button @click="who='child1'">首頁</button>
        </li>
        <li>
            <button @click="who='child2'">訂單</button>
        </li>
        <li>
            <button @click="who='child3'">商品</button>
        </li>
    </ul>
    <component :is="who"></component>
</div>

</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是首頁</span>
                    </div>
                `,
            },
            child2: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(255,104,255,0.7)">我是訂單</span>
                    </div>
                `,
            },
            child3: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(104,255,104,0.7)">我是商品</span>
                    </div>
                `,
            }
        }
    })
</script>
</html>

1.首先什麼是keep-alive?

keep-alive是一個抽象元件:它自身不會渲染一個DOM元素,也不會出現在
父元件鏈中;使用keep-alive包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。簡單理解就是:keep-alive用來快取元件,避免多次載入相應的元件,減少效能消耗。

2.keep-alive的作用

通過設定了keep-alive,可以簡單理解為從頁面1跳轉到頁面2後,然後後退到頁面1,只會載入快取中之前已經渲染好的頁面1,而不會再次重新載入頁面1,以及不會再觸發頁面中的created等類似的鉤子函式,除非自己重新重新整理該頁面1。

3.keep-alive的引數

Keep-alive元件提供了include和exclude兩個屬性,允許元件有條件的進行快取。
include: 字串或正則表示式。只有匹配的元件會被快取。
exclude: 字串或正則表示式。任何匹配的元件都不會被快取。

4.什麼時候用到keep-alive,並且怎麼使用

  • 什麼時候用到 keep-alive

如果需要頻繁切換路由,這個時候就可以考慮用keep-alive了,來達到避免資料的重複請求的目的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>keep-alive</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <ul>
        <li>
            <button @click="who='child1'">首頁</button>
        </li>
        <li>
            <button @click="who='child2'">訂單</button>
        </li>
        <li>
            <button @click="who='child3'">商品</button>
        </li>
    </ul>
    <keep-alive>
        <component :is="who"></component>
    </keep-alive>
</div>

</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是首頁</span>
                    </div>
                `,
            },
            child2: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(255,104,255,0.7)">我是訂單</span>
                    </div>
                `,
            },
            child3: {
                template: `
                    <div>
                        <span style="border-bottom: 5px solid rgba(104,255,104,0.7)">我是商品</span>
                    </div>
                `,
            }
        }
    })
</script>
</html>

五:slot 插槽

1.基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>slot 插槽</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <child>
        <h6>Hello World</h6>
    </child>
</div>

</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child: {
                template: `
                    <div>
                        <slot></slot>
                        <span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是元件的原內容</span>
                        <slot></slot>
                    </div>
                `,
            },
        }
    })
</script>
</html>

2.小案例(通過插槽實現在1個元件中控制另1個元件的顯示隱藏)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>slot 插槽</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!--通過插槽實現在一個元件中控制另一個元件的顯示隱藏-->
    <child1>
        <button @click="isShow=!isShow">顯示/隱藏元件2</button>
    </child1>

    <child2 v-if="isShow"></child2>
</div>
</body>
<script>
    Vue.component('child1', {
        template: `<div>
          元件1
          <slot></slot>
        </div>`,

    })
    Vue.component('child2', {
        template: `<div>
          <h3>元件2</h3>
        </div>`,

    })
    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true
        }

    })
</script>
</html>

3.具名插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>具名插槽</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!-- 具名插槽,把p標籤給a插槽,div標籤給b插槽-->
    <child>
        <p slot="a">我是具名插槽a插入的內容</p>
        <div slot="b">我是具名插槽b插入的內容</div>
    </child>
</div>
</body>
<script>
    Vue.component('child', {
        template: `<div>
            <slot name="a"></slot>
            <hr>
            <span style="border-bottom: 5px solid rgba(255,104,104,0.7)">我是元件的原內容</span>
            <hr>
            <slot name="b"></slot>
        </div>`,

    })
    var vm = new Vue({
        el: '#box',
        data: {}

    })
</script>
</html>

可以指定標籤放在某個插槽的位置