• 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- 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- 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- 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>

    可以指定标签放在某个插槽的位置

     
  • 相关阅读:
    关于because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified报错的解决方案
    对不起,这是一篇负能量爆棚的文章
    selenium启动报错“ incorrect JSON status mapping for 'unknown error' (500 expected)”
    解决关于win10下eclipse代码格式化不生效问题
    递归遍历所有xml的节点及子节点
    性能调优-CPU方面,内存方面
    二进制日志备份与恢复,快照备份,复制
    逻辑备份,mysqldump,SELECT…INTO OUTFILE,恢复
    备份与恢复概述,冷备,热备
    分布式事务,不好的事务习惯
  • 原文地址:https://www.cnblogs.com/ltyc/p/14152047.html
Copyright © 2020-2023  润新知