• Day 83 VUE——组件、插槽、生命周期


    VUE——组件

    局部组件

    创建子组件、挂载子组件、调用子组件
    注意:在组件中,这个 data 必须是一个函数,返回一个对象。
    <div id="app">
        <!-- 3、使用组件 -->
        <app></app>
    </div>
    <script src="./vue.js"></script>
    <script>
        // 组件
        // 创建子组件、挂载子组件、调用子组件
        ///1、创建组件
        const app={
            data(){
                return {
                    msg:'这是第一个局部组件'
                }
            },
            template:
                `
                <div>
                    <h2>{{ msg }}</h2>
                    <button @click='handClick'>改变</button>
                </div>
                `,
            methods:{
                handClick(){
                    this.msg = '修改局部组件'
                }
            }
        }
        new Vue({
            el:'app',
            data:{
    
            },
            // 2、挂载组件
            components:{
                app
            }
        })
    </script>
    View Code

    全局组件

    // 全局组件
    // 每个全局组件都需要定义一次 Vue.component
    // 全局变量的使用:可以在任意 template 中进行引入。
    // 引入方式:<Vheader></Vheader> or <Vconter />
    // 使用手法:在任意 template 中引入
    
    // 第一个参数:组件名(Vheader)
    // 第二个参数:配置
    Vue.component(
        'Vheader',{
            template:`
            <div>
                我是导航组件
            </div>`
        }
    )
    
    Vue.component(
        'Vsider',{
            template:`
            <div>
                我是侧边栏组件
            </div>`
        }
    )
    View Code

    组件通信

    父传子

    父传子:通过 props 来进行通信

    1.在子组件中声明 props 接收在父组件挂载的属性
    2.可以在子组件的 template 中任意使用
    3.在父组件绑定自定义的属性

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <parent></parent>
        </div>
        <script src="./vue.js"></script>
        <script>
            // 父传子:通过 props 来进行通信
            
            // 1.在子组件中声明 props 接收在父组件挂载的属性 
            // 2.可以在子组件的 template 中任意使用
            // 3.在父组件绑定自定义的属性
            
            // 全局组件为子组件
            Vue.component(
                'children',{
                    template:`
                        <div>
                            <h3>这是子组件</h3>
                            <h3>{{ childData }}</h3>
                        </div>
                    `,
                    props:['childData']
                }
            )
    
            // 局部组件为父组件
            const parent = {
                data(){
                    return {
                        msg:'这是父组件'
                    }
                },
                template:`
                <div>
                    <children :childData='msg'></children>
                    
                </div>
                `,
    
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    parent
                }
            })
        </script>
    </body>
    </html>
    View Code

    子传父

    在父组件中,子组件上绑定自定义事件
    在子组件中,触发原生的事件,在事件函数通过 this.$emit 触发自定义事件
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <parent></parent>
        </div>
        <script src="./vue.js"></script>
        <script>
            // 子传父
            // 在父组件中,子组件上绑定自定义事件
            // 在子组件中,触发原生的事件,在事件函数通过 this.$emit 触发自定义事件
            
            // 全局组件为子组件
            Vue.component(
                'child',{
                    template:`
                    <div>
                        <h3>这是子组件</h3>
                        <input type="text" @input = 'handleInput'>
                    </div>
                    `,
                    methods:{
                        handleInput(e){
                            const val = e.target.value
                            this.$emit('inputHand',val)
                        }
                    }
                }
            )
    
    
            // 局部组件为父组件
            const parent = {
                data(){
                    return {
                        msg:'这是父组件',
                        newVal:''
                    }
                },
                methods:{
                    input(newVal){
                        this.newVal = newVal
                    }
                },
                template:`
                <div>
                    <h3>{{ msg }}</h3>
                    <p>显示:{{ newVal }}</p>
                    <child @inputHand='input'></child>
                </div>
                `
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    parent
                }
            })
        </script>
    </body>
    </html>
    View Code

    平行组件通信

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <!-- <app2></app2>
            <app1></app1> -->
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            // 平行组件
            const bus = new Vue();
    
            Vue.component('app1',{
                data(){
                    return{
                        msg:0
                    }
                },
                template:`
                <div>
                    <h3>msg:{{ msg }}</h3>
                </div> 
                `,
                created(){
                    // $on 绑定事件
                    bus.$on('add',(n)=>{
                        this.msg += n
                    }) 
                }
            })
    
            Vue.component('app2',{
                data(){
                    return{
                    
                    }
                },
                template:`
                <div>
                    <button @click='handClick'>+1</button>
                </div> 
                `,
                methods:{
                    handClick(){
                        bus.$emit('add',1);
                    }
                }
                
            })
    
    
            const App = {
                data(){
                    return{
    
                    }
                },
                template:`
                    <div>
                        <app2></app2>
                        <app1></app1>
                    </div>
                `,
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
    
            })
        </script>
    </body>
    </html>
    View Code

    组件通信其它方式(provide和inject)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            // provide 提供变量
            // inject 注入变量
            // provide 在父组件中提供变量,然后在子组件中使用 inject 注入变量,无论组件嵌套有多深
            Vue.component('app1',{
                data(){
                    return{
    
                    }
                },
                inject:['msg'],
                template:`
                <div>
                    <h3>{{ msg }}</h3>
                </div> 
                `,
                created(){
                    console.log(this.msg)
                    // 还可以通过 $pareent $chilred 的方式来获取父组件、子组件的值
                    console.log(this.$parent.$parent)
                    console.log(this.$children)
                }
            })
    
            const App = {
                data(){
                    return{
    
                    }
                },
                template:`
                    <div>
                        <app1></app1>
                    </div>
                `,
                provide(){
                    return{
                        msg:'父组件中的数据'
                    }
                }
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
    
            })
        </script>
    </body>
    </html>
    View Code

    组件异步加载

    html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script type="module">
            const App = {
                data(){
                    return{
                        isShow:false
                    }
                },
                methods:{
                    handClick(){
                        this.isShow = !this.isShow
                    }
                },
                components:{
                    Test:()=>import('./Test.js')
                },
                template:`
                    <div>
                        <Test v-if="isShow"></Test>
                        <button @click='handClick'>异步加载</button>
                    </div>
                    
                `
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    View Code

    js文件

    export default {
        data(){
            return{
                msg:'亦双弓'
            }
        },
        template:`
            <div>
                <h3>{{msg}}</h3>
            </div>
        `
    }
    View Code

    VUE——插槽

    匿名插槽

     
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            Vue.component('MBtn',{
                template:`
                    <button>
                        <slot></slot>
                    </button>
                `
            })
    
            const App = {
                data(){
                    return{
                        title:'父组件'
                    }
                },
                template:`
                    <div>
                        <m-btn>登录</m-btn>
                        <m-btn><a href='#'>注册</a></m-btn>
                    </div>
                `
    
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    View Code

    注意:匿名插槽 <slot></slot> 只能出现一次,如果出现多次,则会出造成以下情况。

    <button>
      <slot></slot> 
      <slot></slot> 
      <slot></slot>
    </button>

    具名插槽

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            Vue.component('MBtn',{
                // 插入组件的顺序和命名时的顺序无关
                template:`
                    <button>
                        <slot name = 'login'></slot> 
                        <slot name = 'register'></slot>
                        <slot name = 'submit'></slot> 
                    </button>
                `
            })
    
            const App = {
                data(){
                    return{
                        title:'父组件'
                    }
                },
                template:`
                    <div>
                        <m-btn>
                            <template slot = 'login'>
                                登录
                            </template>
                        </m-btn>
                        <m-btn>
                            <template slot = 'submit'>
                                提交
                            </template>
                        </m-btn>
                        <m-btn>
                            <template slot = 'register'>
                                注册
                            </template>
                        </m-btn>
                        
                    </div>
                `
    
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    View Code

    注意:插入组件的顺序和命名时的顺序无关

    作用域插槽

    有时让插槽内容能够访问子组件中才有的数据是很有用的

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id='app'>
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            // 要求:
            // 1.之前数据格式和应用接口不变,正常显示
            // 2.新功能模块:增加对勾
            const todoList = {
                data(){
                    return{
    
                    }
                },
                props:{
                    todos: Array,
                    defaultValue:[]
                },
                template:`
                    <ul>
                        <li v-for='item in todos' :key='item.id'>
                            <slot :itemValue = 'item'>
                                
                            </slot>
                            {{ item.title }}
                        </li>    
                    </ul>
                `
            }
    
            const App = {
                data(){
                   return{
                        todoList:[
                            {
                                title:'你的玫瑰',
                                isComplate:true,
                                id:1
                            },
                            {
                                title:'独善其身',
                                isComplate:false,
                                id:2
                            },
                            {
                                title:'失忆的金鱼',
                                isComplate:false,
                                id:3
                            },
                            {
                                title:'浪费',
                                isComplate:true,
                                id:4
                            },
                        ]
                    }
                },
                components:{
                    todoList
                },
                template:`
                    <todoList :todos="todoList">
                        <template v-slot='data'>
                            <input type="checkbox" v-model="data.itemValue.isComplate" />
                        </template>
                    </todoList>
                `,
            }
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    View Code

    生命周期

    生命周期钩子

    beforeCreate
    created                                         重要
    beforeMount
    mounted                                         重要
    beforeUpdate
    updated                                         重要
    activated       组件激活    配合 keep-alive     需要掌握 
    deactivated     组件停用    配合 keep-alive     需要掌握
    beforeDestroy   销毁之前                        需要掌握
    destroyed       销毁完成                        需要掌握
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            .active{
                color: red;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
    
            /*
                beforeCreate
                created                                         重要
                beforeMount
                mounted                                         重要
                beforeUpdate
                updated                                         重要
                activated       组件激活    配合 keep-alive     需要掌握 
                deactivated     组件停用    配合 keep-alive     需要掌握
                beforeDestroy   销毁之前                        需要掌握
                destroyed       销毁完成                        需要掌握
            */
    
            Vue.component('Test',{
                data(){
                    return{
                        msg:'亦双弓',
                        isRed:false
                    }
                },
                methods:{
                    handClick(){
                        this.msg = 'ysg';
                        this.isRed = true;
                    }
                },
                template:`
                    <div>
                        <button @click='handClick'>改变</button>
                        <h3 :class="{active:isRed}">{{msg}}</h3>
                    </div>
                `,
                beforeCreate(){
                    console.log('组件创建之前',this.$data)
                },
                created(){
                    // 这时可以做一件非常重要的事情:发送 ajax 请求后端数据
                    console.log('组件创建完成',this.$data)
                },
                beforeMount(){
                    // 即将挂载
                   console.log('DOM挂载之前', document.getElementById('app'))
                },
                mounted(){
                    console.log('DOM挂载完成', document.getElementById('app'))
                },
                beforeUpdate(){
                    // 获取更新之前 原始的DOM
                    console.log('更新之前的DOM',document.getElementById('app').innerHTML)
                },
                updated(){
                    // 获取更新之后 最新的DOM
                    console.log('更新之后的DOM',document.getElementById('app').innerHTML)
                },
                beforeDestroy(){
                    // 销毁之前
                    console.log('销毁之前')
                },
                destroyed(){
                    // 销毁完成
                    console.log('销毁完成')
                },
                activated(){
                    console.log('组件激活')
                },
                deactivated(){
                    console.log('组件停用')
                },
            })
    
            const App = {
                data(){
                    return{
                        isShow:true
                    }
                },
                components:{
    
                },
                methods:{
                    handClick(){
                        this.isShow = !this.isShow
                    }
                },
                template:`
                    <div>
                        <keep-alive>
                            <Test v-if="isShow"></Test>    
                        </keep-alive>
                        
                        <button @click='handClick'>销毁与否</button>
                    </div>
                    
                `
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    生命周期钩子示例

    refs的使用

    1.如果给标签添加 ref,获取的是真实的 DOM 节点
    2.如果给子组件添加 ref,获取的是当前子组件对象

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script type="module">
    
            Vue.component('Test',{
                data(){
                    return{
                        msg:'亦双弓'
                    }
                },
                template:`
                    <h3>{{msg}}</h3>
                `
            })
    
            const App = {
                data(){
                    return{
                        
                    }
                },
                mounted(){
                    // 1.如果给标签添加 ref,获取的是真实的 DOM 节点
                    // 2.如果给子组件添加 ref,获取的是当前子组件对象
                    console.log(this.$refs.btn);
                    console.log(this.$refs.test);
                    // 加载界面 自动获取焦点
                    this.$refs.input.focus();
                    
                },
                template:`
                    <div>
                        <Test ref='test'></Test>
                        <input type="text" ref="input"></input>
                        <button ref='btn'>改变</button>
                    </div>
                    `
            }
    
            new Vue({
                el:'#app',
                data:{
    
                },
                components:{
                    App
                }
            })
        </script>
    </body>
    </html>
    ref 的使用

    nextTick

    nextTick的使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <h3>{{ msg }}</h3>
        </div>
        <script src="./vue.js"></script>
        <script type="module">
            const vm = new Vue({
                el:'#app',
                data:{
                    msg:'亦双弓'
                },
            })
    
            vm.msg = 'new msg'
            console.log(vm.$el.textContent) // 获取的还是没变化前的 msg
            Vue.nextTick(()=>{
                // 为了数据变化之后等待 vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick 在当前的
                // 回调函数中可以获取最新的 DOM
                console.log(vm.$el.textContent) // 获取的是变化后的 msg
            })
    
        </script>
    </body>
    </html>
    nextTick 的简单使用

    nextTick的应用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <App></App>
        </div>
        <script src="./vue.js"></script>
        <script>
            /*
                要求:
                    在页面拉取一个接口,这个接口返回一些数据,这些数据是这个页面的一个浮层组件要依赖的,
                    然后在接口已返回数据就展示了这个浮层组件,
                    并在展示的同时,上报一些数据给后台(这些数据是父组件从接口拿的)。
                    这个时候,神奇的事情发送了,虽然拿到了数据,但是浮层展现的时候,这些数据还未更新到组件上去,上报时报
            */
            const Pop = {
                data(){
                    return{
                        isShow:false
                    }
                },
                props:{
                    name:{
                        type:String,
                        default:''
                    }
                },
                template:`
                    <div v-if='isShow'>
                        {{ name }}
                    </div>
                `,
                methods:{
                    show(){
                        this.isShow = true // 弹窗组件展示
                        console.log(this.name)
                    }
                },
            }
            const App = {
                data(){
                    return{
                        name:''
                    }
                },
                created(){
                    // 模拟异步请求
                    setTimeout(()=>{
                        this.name = 'ysg'
                        this.$nextTick(()=>{
                            this.$refs.pop.show()
                        })
                    },1000)
                },
                components:{
                    Pop
                },
                template:`
                <pop ref='pop' :name="name"></pop>
                `
            }
            new Vue({
                el:'#app',
                components:{
                    App
                }
            })
    
        </script>
    </body>
    </html>
    nextTick的应用

    mixin

    mixin混入偷懒技术

    mixin 来分发 Vue 中可复用的功能

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <h3>
                {{ msg }}
            </h3>
        </div>
    
        <script src="./vue.js"></script>
        <script>
            const myMixin={
                data(){
                    return{
                        msg:123     // 界面上就会显示 123
                    }
                },
                created(){
                    this.sayHello()
                },
                methods:{
                    sayHello(){
                        console.log('Hello 123')  // console 中就会显示 Hello world
                    }
                }
            }
    
            new Vue({
                el:'#app',
                data:{
                    title:'亦双弓',
                    msg:'ysging'    // 假如这里也有 msg 就会优先显示这里的
                },
                created(){
                    console.log('111111')   // created() 会同时显示,假如这里存在 this.sayHello(),则会调用两次 这里的 sayHello()
                },
                mixins:[myMixin]      // 数组,可放入多个混入对象
            })
    
        </script>
    </body>
    </html>
    mixin混入偷懒技术

    mixin混入技术应用

    创建全局的 mixin 要格外的小心,因为每个组件实例创建时,都会被调用

    使用比较少
    Vue.mixin({

    })

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
    
        </div>
        <script src="./vue.js"></script>
        <script>
            /*
                创建全局的 mixin 要格外的小心,因为每个组件实例创建时,都会被调用
                使用比较少
                Vue.mixin({
    
                })
            */
            const Temp = {
                data(){
                    return{
                        isShow:false
                    }
                },
                methods:{
                    toggleShow(){
                        this.isShow = !this.isShow
                    }
                }
            }
    
            const app2 = {
                template :`
                    <div v-if='isShow'> App2 组件 </div>
                `,
                // 局部的 mixin
                mixins: [Temp]
            }
    
            const app1 = {
                template :`
                    <div v-if='isShow'> App1 组件 </div>
                `,
                mixins: [Temp]
            }
    
            new Vue({
                el:'#app',
                data:{
                },
                components:{
                    app1, app2
                },
                template:`
                    <div> 
                        <button @click='handleApp1'>app1</button>
                        <button @click='handleApp2'>app2</button>
                        <app1 ref='a1'></app1>
                        <app2 ref='a2'></app2>
                    </div>
                `,
                methods:{
                    handleApp1(){
                        this.$refs.a1.toggleShow()
                    },
                    handleApp2(){
                        this.$refs.a2.toggleShow()
                    },
                }
            })
    
        </script>
    </body>
    </html>
    mixin混入技术应用

    对象变更检测注意事项

    Vue 不能检测对象属性的添加与删除

    如果想要动态 添加与删除 属性,使用以下方法
    // 方法一
    this.$set(this.user,'age',20);

    // 方法二 添加多个响应式属性
    this.user = Object.assign({},this.user,{
      age:20,
      phone:123456789
    })

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">
            <h3>
                {{ user.name }} {{ user.age }} {{ user.phone }} 
            </h3>
            <button @click='handClick'>添加属性</button>
        </div>
        <script src="./vue.js"></script>
        <script>
            // Vue 不能检测对象属性的添加与删除
            new Vue({
                el:'#app',
                data:{
                    user:{}
                },
                created(){
                    setTimeout(()=>{
                        this.user = {
                            name:'张三',
                        }
                    },2000)
                },
                methods:{
                    handClick(){
                        // this.user.age = 20
                        // 如果想要动态 添加与删除 属性,使用以下方法
                        // 方法一
                        this.$set(this.user,'age',20);
                        // 方法二 添加多个响应式属性
                        this.user = Object.assign({},this.user,{
                            age:20,
                            phone:123456789
                        })
    
                    }
                }
            })
    
        </script>
    </body>
    </html>
    添加响应式数据
  • 相关阅读:
    集群资源队列监控:Grafana
    1
    3月9号
    jmx
    日常笔记
    nsenter命令简介
    一天2小时
    postgresql Centos7部署
    笔记5
    1
  • 原文地址:https://www.cnblogs.com/ysging/p/13300412.html
Copyright © 2020-2023  润新知