vue生命周期钩子及组件

生命周期钩子

每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

生命周期图示

在这里插入图片描述
部分参考(https://segmentfault.com/a/1190000008010666?utm_source=tag-newest)
beforecreated:el 和 data 并未初始化
created:完成了 data 数据的初始化,el没有
beforeMount:完成了 el 和 data 初始化
mounted :完成挂载
另外在标红处,我们能发现el还是 {{message}},这里就是应用的 Virtual DOM(虚拟Dom)技术,先把坑占住了。到后面mounted挂载的时候再把值渲染进去。
在这里插入图片描述
在这里插入图片描述
这里我们在 chrome console里执行以下命令

app.message= ‘yes !! I do’;
下面就能看到data里的值被修改后,将会触发update的操作。
在这里插入图片描述
destroy 相关
有关于销毁,暂时还不是很清楚。我们在console里执行下命令对 vue实例进行销毁。销毁完成后,我们再重新改变message的值,vue不再对此动作进行响应了。但是原先生成的dom元素还存在,可以这么理解,执行了destroy操作,后续就不再受vue控制了。

app.$destroy();
在这里插入图片描述
这么多钩子函数,我们怎么用呢?
beforecreate : 举个例子:可以在这加个loading事件
created :在这结束loading,还做一些初始化,实现函数自执行
mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
beforeDestroy: 你确认删除XX吗? destroyed :当前组件已被删除,清空相关内容

组件

组件是可复用的 Vue 实例,且带有一个名字,每一个组件只能有一个根节点。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用。因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。可以在组件内部继续使用vue的其他方法比如:lifeCircle,filter,computed,在一个vue实例中 每一个组件都是独立存在的,它都有自己一套固定的生命周期函数和data以及其他vue的可操作属性和方法

组件的复用

你可以将组件进行任意次数的复用,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。

data必须是一个函数

data 表示组件中使用的数据,组件中的数据必须是一个function,其返回值为data的值,(一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,如果 Vue 没有这条规则,点击一个按钮就可能会影响到其它所有实例)。

组件的组织

为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。下面是通过 Vue.component 全局注册的:

Vue.component(‘my-component-name’, {
// … options …
})

局部组件与全局组件

在vue中使用组件需要先引入,通过在实例中使用components节点进行设置, 此种定义组件的方式叫局部组件
全局组件
// 参数一 组件的名字
// 参数二 一个对象 ,用来设置组件的属性
// 全局组件定义好之后可以直接使用 不需要在components中做注册
Vue.component(‘aaa’, {
template: <h5>这是一个组件</h5>
})
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
注意:在vue中如果使用驼峰命名的时候 在template中使用组件的时候需要使用-把单词做分割

<div id="app">
    <Hello-World></Hello-World>//标签不区分大小写,因此可以hello-world
  </div>
  var app = new Vue({
      el: '#app',
      components: {
        HelloWorld: {
          template: `<h5>Hello World!</h5>`
        }
      }
    })

组件之间可以进行嵌套调用

通过this.$attrs可以获取到父组件传递过来的数据, 在使用局部组件的时候必须先进行注册,哪里使用就要在哪里进行注册


   <!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>
    .list-item {
      border: 1px solid deeppink;
      padding: 0.2rem 1rem;
      margin: 0.5rem;
    }
  </style>
</head>
<body>
  <div id="app">
    <list-item :info="book" k="abc" b="1234" v-for="book in books"></list-item>
  </div>
  <script src="./lib/vue.js"></script>
  <script>

    const hello = {
      template: '<h3>Hi!!!!!!!!!!</h3>'
    }
    Vue.component('list-item', {
      template: `<div class="list-item">
        <h5 class="title">{{data.title}}</h5>
        <p class="desc">作者:{{data.author}}</p>
        <book-price :p="data.price"></book-price>
        <hello></hello>
      </div>`,
      data() {
        return {
          data: {
            title: '',
            author: '',
            price: '',
          }
        }
      },
      created() {
        // debugger;
        console.log(this.$attrs) // this.$attrs可以获取到外层组件传递过来的数据
        this.data = this.$attrs.info;
      },
      components: {
        hello,
      },
    })
    Vue.component('book-price', {
      template: `<div>
          <p :style="priceClass">¥{{price}}元</p>
          <hello></hello>
        </div>`,
      data() {
        return {
          priceClass: {
            color: 'red',
            fontSize: '1.5rem',
          },
          price: 0,
        }
      },
      created() {
        console.log(this.$attrs)
        this.price = this.$attrs.p;
      },
      components: {
        hello,
      },
    })
    var app = new Vue({
      el: '#app',
      data: {
        books: [{
          title: '三国演义',
          price: 45.98,
          author: '罗贯中',
        }, {
          title: '水浒传',
          price: 52.31,
          author: '施耐庵',
        }, {
          title: '从你的全世界路过',
          price: 29.82,
          author: '张嘉佳',
        }],
      }
    });
  </script>
</body>
</html>

组件传值

通过$attrs传递的属性值是没有在props数组中定义的属性
a t t r s 是 在 v u e 2.4 之 后 的 版 本 新 增 的 属 性 t h i s . attrs是在vue2.4之后的版本新增的属性 this. attrsvue2.4this.props可以获取到所有的属性

vue开发常见传值方式

  1. 子组件传父组件传值
    VUE中子组件向父组件传值 使用事件派发
    在子组件内部使用this.$emit派发事件
    在父组件中使用@或v-on绑定事件
  2. 父组件传子组件传值
    VUE中父组件向子组件进行传值使用props,使用此种方式时在子组件中可以直接通过this.值的名称 进行获取
    下面的例子包含上面两种
<!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>
</head>
<body>
  <div id="app">
    <h5>当前计数器的值为:{{c}}</h5>
    <counter @plusadd="plusAddHandle" :step1="2" step2="3" a="abc" b="我叫MT"></counter>
    <!-- <counter :step1="5"></counter>
    <counter :step1="7"></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;
          this.$emit('plusadd', this.count); // 派发自定义事件
        }
      },
      props: ['step1', 'step2'],
      created() {
        // debugger
        console.log(this.$props);
        console.log(this.$attrs);
        console.log(this.step1);
      }
    })
    var app = new Vue({
      el: '#app',
      data: {
        c: 0,
      },
      methods: {
        plusAddHandle(params) {
          this.c = params;
        }
      }
    })
  </script>
</body>
</html>
  1. 非父子组件传值
    用下面的方式:事件总线

动态组件-事件总线


在上述示例中,currentTabComponent 可以包括已注册组件的名字,或一个组件的选项对象。
为了解决非父子组件之间的传值问题,引入事件总线
在vue中使用一个空白的Vue对象作为一个EventBus,用来做事件的监听和派发
var e v e n t B u s = n e w V u e ( ) ; / / 使 用 一 个 空 白 的 V U E 实 例 作 为 中 间 媒 介 V u e . p r o t o t y p e . eventBus = new Vue(); // 使用一个空白的VUE实例作为中间媒介 Vue.prototype. eventBus=newVue();//使VUEVue.prototype.eventBus = $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>


    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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue生命周期钩子函数指的是在组件实例化、渲染、更新和销毁等不同阶段执行的一些特定函数。下面是 Vue 组件生命周期钩子函数及其执行顺序: 1. beforeCreate:在实例创建之前被调用。此时组件的数据和方法都还未初始化。 2. created:在实例创建完成之后被调用。此时组件的数据已经初始化,但 DOM 还未渲染。 3. beforeMount:在组件挂载到 DOM 之前被调用。此时模板已经编译完成,但还未挂载到页面中。 4. mounted:在组件挂载到 DOM 后被调用。此时组件已经被渲染并插入到页面中,可以进行 DOM 操作。 5. beforeUpdate:在数据更新之前被调用。此时组件还未重新渲染,但数据已经更新。 6. updated:在数据更新之后被调用。此时组件已经重新渲染,可以进行 DOM 操作。 7. beforeDestroy:在组件销毁之前被调用。此时组件还存在,可以进行一些清理工作。 8. destroyed:在组件销毁之后被调用。此时组件已经从 DOM 中移除,事件监听和定时器等资源都已经被销毁。 对于父子组件,它们的生命周期钩子函数的执行顺序如下: 1. 父组件的 beforeCreate 和 created 钩子函数执行。 2. 子组件的 beforeCreate 和 created 钩子函数执行。 3. 子组件的 beforeMount 钩子函数执行。 4. 子组件的 mounted 钩子函数执行。 5. 父组件的 beforeMount 钩子函数执行。 6. 父组件的 mounted 钩子函数执行。 7. 数据更新时,先执行父组件的 beforeUpdate 钩子函数,然后执行子组件的 beforeUpdate 钩子函数,再执行子组件的 updated 钩子函数,最后执行父组件的 updated 钩子函数。 8. 组件销毁时,先执行父组件的 beforeDestroy 钩子函数,然后执行子组件的 beforeDestroy 钩子函数,最后执行子组件的 destroyed 钩子函数,再执行父组件的 destroyed 钩子函数。 这是 Vue 组件生命周期钩子函数的一般执行顺序,但在实际开发中可能会有特殊情况,需要根据具体需求来使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值