美文网首页
vue生命周期和组件间传值

vue生命周期和组件间传值

作者: 没了提心吊胆的稗子 | 来源:发表于2019-07-31 22:29 被阅读0次

    生命周期

    new Vue() 初始化一些事件和生命周期 例如:vm.$on, vm.$once, vm.$emit
    beforeCreate 初始化之前,会先把一些数据方法放在实例中,还没初始化完,不能操作数据,一般用不到
    created 数据,方法初始化完成,可以操作数据,实现响应式绑定,此处一般ajax获取数据
    必须有el属性(有编译的元素),才能进行挂载,只能有一个根元素,如果有template属性(内部html),app(外部html)中的内容就会被覆盖掉,就没有意义了
    beforeMount 挂载之前,没有什么实际意义,会用vm.$el替换el
    mounted 挂载完成,数据和模板挂载好了,真实DOM渲染完了,可以操作DOM
    beforeUpdate 更新之前,页面依赖的数据有变化就会开始更新
    updated 更新之后,一般用watch方法替代这两个方法
    beforeDestory 销毁之前,开始移除一些定时器和事件绑定等操作,方法还没销毁,
    destoryed 销毁完成

    this.$data:vm上的数据
    this.$watch:监控
    this.$el:当前el元素
    this.$set:后添加的属性实现响应式变化
    this.$options:实例上的属性,包括内置的还有自定义的
    this.$refs:所有ref的集合,带ref属性的标签,如果不是通过v-for循环出来的DOM元素,只能获取一个
    this.$nextTick():异步方法,等待渲染完成后获取vm,数据变化后想获取真实dom,需要等待页面获取完成后再去获取,因此所有dom操作最好都放在this.$nextTick()

    mounted(){
      // console.log(document.getElementsByTagName('p')[0].innerHTML);
      console.log(this.$refs.message);
      console.log(this.$refs.wrap);
      this.arr = [1,2,3,4,5]; // dom的渲染是异步的
      this.$nextTick(function () {
      // 数据变化后想获取真实dom,需要等待页面获取完成后再去获取
          console.log(this.$refs.wrap.children.length); // 5
       });
      console.log(this.$refs.wrap.children.length); // 3
    }
    

    组件化开发

    组件化开发可以提高开发效率,方便重复利用,便与协同开发,更容易被管理和维护。一般根据功能可分为两种:
    1、页面级组件,一个页面是一个组件
    2、基础组件,将可复用的部分抽离出来
    vue中,一个自定义标签就会被看成一个组件
    根据用法划分:
    全局组件:声明一次可以在任何地方使用,写插件的时候用的多
    局部组件:必须要声明这个组件属于哪一部分
    声明组件的时候,标签名不要大写,多个单词用- 组件名和定义的名字相同是可以的(首字母可以大写)
    html中用-,JS中转驼峰也是可以的
    组件中的data必须是函数类型的,返回一个实例作为组件中的数据

    <body>
    <!--分类 页面级组件 一个页面是一个组件-->
    <!--将可复用的部分抽离出来  基础组件-->
    
    <div id="app">
    <my-vue></my-vue>
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 一个对象可以看成一个组件
        Vue.component('my-vue', {
            template: '<div>{{msg}}</div>',
            data(){
                return {msg: 'vue学习'}
            }
        });
    </script>
    </body>
    

    局部组件
    局部组件使用的三部曲
    1、创建组件
    2、注册组件
    3、引用组件
    组件是相互独立的,不能直接跨作用域,vm这个实例也是一个组件,组件中拥有生命周期函数,如果组件共用了数据会导致同时更新,因此要求data必须是函数类型的。
    子组件不能直接使用父组件的数据(组件间数据传递),组件理论上可以无限嵌套

    <body>
    <div id="app">
        <component1></component1>
        <component2></component2>
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 局部组件使用的三部曲
        // 1、创建组件
        // 2、注册组件
        // 3、引用组件
        let component1 = {
            template: '<div>{{msg}}</div>',
            data(){
               return {msg: '组件2'}
            }
        };
        let component2 = {
            template: '<div>组件2</div>',
        };
        let vm = new Vue({
            el: '#app',
            components:{
                component1,
                component2
            },
            data: {}
        });
    </script>
    

    组件间的嵌套:
    1、被调用的子组件必须先定义,否则就拿不到。
    2、哪里要用当前组件,就在哪里通过components注册,
    3、需要在调用的组件中通过标签的形式引入
    理论上是无限嵌套的,单位了好维护,一般最多嵌套3层

    <div id="app">
        <!--<div>parent-->
            <!--<div>child-->
                <!--<div>grandson</div>-->
            <!--</div>-->
        <!--</div>-->
        <parent>
            <child>
                <grandson></grandson>
            </child>
        </parent>
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let grandson = {
                template: `<div>grandson</div>`
            },
            child = {
                template: `<div>child<grandson></grandson></div>`,
                components:{
                    grandson
                }
            },
            parent = {
            template: `<div>parent<child></child></div>`,
            components: {
                child
            }
        };
        let vm = new Vue({
            el: '#app',
            components:{
                parent,
            },
            data: {}
        });
    </script>
    </body>
    

    父组件给子组件传值:属性传递,:money=""是传值的,传了一个空值,所以不会用到default,不在子组件定义这个属性,这才算不传值
    required: true:表示该值必须传递,不穿就发警告,不能与默认值default同时出现。
    校验时不会阻断代码的执行,只会出现警告
    还可以自己定义校验信息,用validator方法,里面的参数就是当前传递的值,返回true表示通过反之不通过。(用的8多)

    <body>
    <div id="app">
        parent: {{money}}
        <!--m属于子,属性值属于父-->
        <!--当前组件的属性=父级的值-->
        <child :money="money"></child>
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 父传子
        let vm = new Vue({
            el: '#app',
            data: {
                money: 100,
                a: 400
            },
            components: {
                child: {
                    // 会在当前子组件上声明一个m属性,值是父组件的
                    // 数组的形式可以直接取值,但无法校验
                    // props: ['money'], // this.m = money变量 this->child
                    // 对象的形式可以校验
                    props: {
                        // 子父组件中的属性名不能重复,控制台也会报错
                        // 父组件的会覆盖子组件的值
                        // 可以加个default值,不传值的时候就用默认值
                        money: {
                            // 判断传递值的类
                            // 如果不带冒号:,得到的肯定是字符串类型
                            // 类型不对页面上依旧会显示,但控制台会报类型错误
                            type: [Number],
                            // default: 0
                            required: true,
                            validator(val){ // 参数是当前传递的值,返回true表示通过
                                return val > 300;
                            }
                        }
                    },
                    template: '<div>child: {{money}}</div>'
                }
            }
        });
    </script>
    </body>
    

    子组件给父组件传值:通过发布订阅的模式,父亲绑定一些事件,儿子触发这个事件,将参数传递过去,单向数据流 父组件数据刷新,子组件就刷新,不能子组件直接改父组件的值,要想这样,就需要子组件先通知父组件要修改值,父组件再去修改
    在本例子中,子组件通过点击事件触发($emit)自己的child-msg方法,而该方法又触发了父组件的moreMoney方法执行,这样一来就实现了子组件向父组件传值

    <body>
    <div id="app">
        parent: {{money}} <button @click="lessMoney">少要点</button>
        <!--m属于子,属性值属于父-->
        <!--当前组件的属性=父级的值-->
        <!--刚刚那个事件是父级的,订阅需要在子级做-->
    
        <child :money="money" @child-msg="moreMoney"></child>
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                money: 400,
            },
            methods: {
                moreMoney(val){
                    this.money = val;
                },
                lessMoney(){
                    this.money = 200;
                }
            },
            components: {
                child: {
                    props: ['money'],
                    template: '<div>child: {{money}} 
                     <button @click="getMoney">再来点</button></div>',
                    methods: {
                        getMoney(){ // 触发自己的自定义事件让父组件的方法执行
                            this.$emit('child-msg', 800);
                        }
                    }
                }
            }
        });
    </script>
    </body>
    

    sync语法糖的用法

    <child :money="money" @update:money="val=>this.money=val"></child>
    same as
    <child :money.sync="money"></child>
    

    子父组件声明周期
    父组件需要等到子组件挂载完成(mounted)之后才会触发挂载

    mounted(){
        console.log(this.$refs.child.$el.innerHTML); 
        // 1 2 3
        // 因为存在DOM映射,所以页面上的数据实时变化,
        // 但是DOM渲染是个异步的过程,这里还新的数据还没有渲染完
        this.$nextTick(() => {
              console.log(this.$refs.child.$el.innerHTML); 
              // 4 5 6
        });
    },
    

    兄弟组件间相互通信
    eventBus一般不用,了解,发布订阅模式失败的原因是因为在不同组件中的this是不一样的,组件2触发,组件1监听,显然是行不通的。发布订阅的执行者应该是同一个才能成功,因此就需要有一个第三方实例eventBus来实现交互。

    let brother1 = {
            template: '<div>{{color}} <button>变绿</button></div>',
            data() {
                return {color: '绿色', old: '绿色'}
            },
            created() {
                // 组件1监听
                this.$on('changeRed', (val) => { // 页面一加载,组件1长一个耳朵来监听
                    this.color = val;
                })
            }
        };
    let brother2 = {
            template: '<div>{{color}} <button @click="change">变红</button></div>',
            data() {
                return {color: '红色', old: '红色'}
            },
            methods: {
                change() {
                    // 组件2发布
                    this.$emit('changeRed', this.old);
                }
            }
    };
    

    eventBus使用,创建一个Vue实例,在兄弟组件中发布订阅都用这个实例来操作即可,但是触发的方法名不能重复,否则就乱套了

    let eventBus = new Vue();
    eventBus.$on('changeRed', (val) => { 
          this.color = val;
    });
    change() {
         eventBus.$emit('changeRed', this.old);
    }
    

    相关文章

      网友评论

          本文标题:vue生命周期和组件间传值

          本文链接:https://www.haomeiwen.com/subject/flvtdctx.html