vue生命周期和组件间传值

生命周期

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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Vue 实例 在文档中经常会使用 vm 这个变量名表示 Vue 实例,在实例化 Vue 时,需要传入一个选项对象,...
    鄙人才疏学浅阅读 577评论 0 1
  • 1.vue基本生命周期 vue源码中最终执行生命周期函数都是调用callHook方法,callHook函数的逻辑很...
    WHU_GIS_LJ阅读 19,621评论 0 13
  • 实例生命周期: beforeCreate:在实例初始化之后,数据观测data observer(props、dat...
    隔壁老王z阅读 36,947评论 0 29
  • 每个vue实例从创建到销毁的过程都是一个生命周期,也会运行对应的钩子函数,下图为Vue生命周期示意图: 1.bef...
    yun_154192阅读 12,624评论 1 7
  • beforeCreate 1 .实例初始化之后2 .this指向创建的实例3 .数据观测,event/watche...
    skoll阅读 1,316评论 1 1