Vue中生命周期钩子函数以及组件之间传值

一 什么是生命周期钩子?

生命周期钩子是在Vue对象生命周期的某个阶段执行的已定义方法。从初始化开始到它被破坏时,对象都会遵循不同的生命阶段。
我们可以使用生命周期钩子在Vue对象生命周期的不同阶段添加我们的自定义代码。它将帮助我们控制在DOM中创建对象时创建的流程,以及更新和删除对象。


图片.png

beforeCreate

Vue对象用新方法实例化。它创建一个Vue类的对象来处理DOM元素。对象的这个生命阶段可以通过beforeCreated 挂钩来访问 。我们可以在这个钩子中插入我们的代码,在对象初始化之前执行。

Created(具有默认特性的对象)

在这个生命阶段,对象及其事件完全初始化。 created 是访问这个阶段并编写代码的钩子。

beforeMount(对象在DOM中适合形状)

这个钩子被调用 beforeMounted。在这个阶段,它检查是否有任何模板可用于要在DOM中呈现的对象。如果没有找到模板,那么它将所定义元素的外部HTML视为模板。

Mounted(DOM已准备就绪并放置在页面内)

一旦模板准备就绪。它将数据放入模板并创建可呈现元素。用这个新的数据填充元素替换DOM元素。这一切都发生在mounted钩子上。

beforeUpdate(更改已完成,但尚未准备好更新DOM)

在外部事件/用户输入beforeUpdate发生更改时,此钩子即 在反映原始DOM元素的更改之前被触发。

Updated(在DOM中呈现的更改)

然后,通过实际更新DOM对象并触发updated,屏幕上的变化得到呈现 。

beforeDestroy(对象准备死掉)

就在Vue对象被破坏并从内存中释放之前, deforeDestroy 钩子被触发,并允许我们在其中处理我们的自定义代码。

Destroyed(对象停止并从内存中删除)

该 destroyed 钩子被成功运行销毁对象上调用。

<!DOCTYPE html>
<html>
<head>
    <title>钩子函数</title>
    <meta charset="utf-8">
    <script src="./lib/vue.js"></script>
<body>

<div id="app">
    <p>{{ message }}</p>
    <input type="button" @click="change" value="更新数据" />
    <input type="button" @click="destroy" value="销毁" />
</div>

<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: {
            message : "Welcome Vue"
        },
        methods:{
            change() {
                this.message = 'Datura is me';
            },
            destroy() {
                app.$destroy();
            }
        },
        beforeCreate: function () {
            console.group('beforeCreate 创建前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //undefined
            console.log("%c%s", "color:red","data   : " + this.$data); //undefined
            console.log("%c%s", "color:red","message: " + this.message);//undefined
        },
        created: function () {
            console.group('created 创建完毕状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el); //undefined
            console.log("%c%s", "color:green","data   : " + this.$data); //[object Object]  =>  已被初始化
            console.log("%c%s", "color:green","message: " + this.message); //Welcome Vue  =>  已被初始化
        },
        beforeMount: function () {
            console.group('beforeMount 挂载前状态===============》');
            console.log("%c%s", "color:green","el     : " + (this.$el)); //已被初始化
            console.log(this.$el); // 当前挂在的元素
            console.log("%c%s", "color:green","data   : " + this.$data); //已被初始化
            console.log("%c%s", "color:green","message: " + this.message); //已被初始化
        },
        mounted: function () {
            console.group('mounted 挂载结束状态===============》');
            console.log("%c%s", "color:green","el     : " + this.$el); //已被初始化
            console.log(this.$el);
            console.log("%c%s", "color:green","data   : " + this.$data); //已被初始化
            console.log("%c%s", "color:green","message: " + this.message); //已被初始化
        },
        beforeUpdate: function () {
            alert("更新前状态");
            console.group('beforeUpdate 更新前状态===============》'); //这里指的是页面渲染新数据之前
            console.log("%c%s", "color:green","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:green","data   : " + this.$data);
            console.log("%c%s", "color:green","message: " + this.message);
            alert("更新前状态2");
        },
        updated: function () {
            console.group('updated 更新完成状态===============》');
            console.log("%c%s", "color:green","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:green","data   : " + this.$data);
            console.log("%c%s", "color:green","message: " + this.message);
        },
        beforeDestroy: function () {
            console.group('beforeDestroy 销毁前状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        destroyed: function () {
            console.group('destroyed 销毁完成状态===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        }
    })
</script>
</body>
</html>
图片.png

点击更新数据


图片.png

点击销毁之后此实例已不存在


图片.png

二 组件之间传值

组件:组件是可复用的 Vue 实例,且带有一个名字,每个组件必须只有一个根元素,data必须是一个函数。
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息,如下图所示:


图片.png

1.父组件通过Prop向子组件传递数据

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。可以用一个 props 选项将需要传递的数据包含在该组件可接受的 prop 列表中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <counter :step1="2"></counter>
    </div>
    <script src="./lib/vue.js"></script>
    <script>
        Vue.component('counter',{
           template:`<button @click="plusHandle">当前计数值: {{count}}</button>` ,
           data(){
               return {
                   count:1,
                   step:1
               }
           },
           methods: {
               plusHandle(){
                   this.count+=this.step1
               }
           },
           props:['step1']
        })
        var app=new Vue({
            el:'#app',
        })
    </script>
</body>
</html>

2.子组件向父组件传值 使用事件派发

在子组件内部使用this.$emit派发事件
在父组件中使用@(v-on)绑定事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <h5>当前计数器的值为:{{c}}</h5>
        <counter @plusadd="plusAddHandle" :step1="2"></counter>
    </div>
    <script src="./lib/vue.js"></script>
    <script>
        Vue.component('counter',{
           template:`<button @click="plusHandle">当前计数值: {{count}}</button>` ,
           data(){
               return {
                   count:0,
                   step:1
               }
           },
           methods: {
               plusHandle(){
                   this.count+=this.step1;
                   this.$emit('plusadd',this.count);
               }
           },
           props:['step1']
        })
        var app=new Vue({
            el:'#app',
            data:{
                c:0,
            },
            methods: {
                plusAddHandle(params){
                    this.c=params;
                }
            }
        })
    </script>
</body>
</html>

3.非父子组件之间的数据传递

为了解决非父子组件之间的传值问题,引入事件总线(EventBus)
在vue中使用一个空白的Vue对象作为一个EventBus,用来做事件的监听和派发

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>动态组件</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
    .nav {
      background-color: deeppink;
      padding: 1.5rem 1rem;
      height: 60px;
    }
    .nav ul {
      margin: 0;
      padding: 0;
    }
    .nav ul li {
      float: left;
      margin: 1.5rem;
      list-style: none;;
    }
    .nav a {
      color: #fff;
      cursor: pointer;
    }
    .nav a.cur {
      color: greenyellow;
    }
    .product {
      border-bottom: 1px solid #ccc;
      padding: 0.2rem 0.5rem;
    }
  </style>
</head>
<body>
  <div id="app">
    <navbar @pagchange="changePageHandle"></navbar>
    <component :is="currentPage"></component>
  </div>
  <script src="./lib/vue.js"></script>
  <script>

    // 事件总线
    // 为了解决非父子组件之间的传值问题,引入事件总线
    //  在vue中使用一个空白的Vue对象作为一个EventBus,用来做事件的监听和派发

    const Nav = {
      template:  `
      <div class="nav">
        <ul>
          <li><a :class="this.selIndex==0? 'cur': ''" @click="navClick(0, 'Home')">首页</a></li>
          <li><a :class="this.selIndex==1? 'cur': ''" @click="navClick(1, 'List')">商品列表页</a></li>
          <li><a :class="this.selIndex==2? 'cur': ''" @click="navClick(2, 'Cart')">购物车【{{cartCount}}】</a></li>
          <li><a :class="this.selIndex==3? 'cur': ''" @click="navClick(3, 'Us')">关于我们</a></li>
        </ul>
      </div>
      `,
      data() {
        return {
          selIndex: 0,
          cartCount: 0
        }
      },
      methods: {
        navClick(index, page) {
          this.$emit('pagchange', page); // 子组件传值到父组件
          this.selIndex = index
        }
      },
      created() {
        this.$eventBus.$on('addToCartEvent', (id) => { 
          console.log(id);
          console.log(this);
          this.cartCount += 1;
        })
      }
    }
    const Home = {
      template: `
      <div>
        <h1>我是首页</h1>
      </div>
      `
    }
    const List = {
      template: `
      <div>
        <div v-for="item in products" class="product">
          <h3>{{item.name}}</h3>
          <p>{{item.price}}<button @click="addToShopCart(item.id)">加入购物车</button></p>
        </div>
      </div>
      `,
      data() {
        return {
          products: [{
            id: 1,
            name: 'iphone18',
            price: 19999,
          }, {
            id: 2,
            name: 'vivo 32',
            price: 5200
          }, {
            id: 3,
            name: 'redmi 10',
            price: 3000,
          }]
        }
      },
      methods: {
        addToShopCart(id) {
          this.$eventBus.$emit('addToCartEvent', id); // 使用$eventBus对象派发一个事件
        }
      }
    }
    const Cart = {
      template: `
      <div>
        <h1>我是购物车</h1>
      </div>
      `
    }
    const Us = {
      template: `
      <div>
        <h1>关于我们</h1>
      </div>
      `
    }
    var $eventBus = new Vue(); // 使用一个空白的VUE实例作为中间媒介
    Vue.prototype.$eventBus = $eventBus; // 此种定义的属性可以在实例中进行访问
    var app = new Vue({
      el: '#app',
      components: {
        navbar: Nav,
        Home,
        List,
        Cart,
        Us
      },
      data: {
        currentPage: 'Home'
      },
      methods: {
        changePageHandle(page) {
          this.currentPage = page;
        }
      }
    })
  </script>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351