跳至主要內容

组件

Emilia Zhen大约 6 分钟vue

组件

组件就是对视图的封装,方便重复使用
模块是对功能逻辑的封装

方式一

Vue.extend结合Vue.component创建

//利用Vue.extend()创建一个组件模板对象
var login = Vue.extend({ template: '<div>登录</div>' })
//使用Vue.component()注册组件
Vue.component('myLogin', login)
<my-login></my-login>

方式二

Vue.component创建

Vue.component('myRegister', { template: '<div>注册</div>' })
<my-register></my-register>

方式三

component结合template方式创建

Vue.component('account', { template: '#account' })
<template id="account">
  template需要写在#app之外
  <div>帐号</div>
</template>

<account></account>
  • 模板template中只能有一个根节点,组件的名字采用驼峰命名法就需要加上'-'
  • Vue.extend()函数返回一个组件构造器,参数里面是配置项
  • Vue.component('indexA',{..})注册组件,参数1组件名,参数2配置对象

组件中data必须是function,必须返回一个对象

父子组件

<template id="question">
  <div>
    <h3>Question {{ num | fmtNum }} : ... ? Winner is {{ rightOne }}</h3>
    <button @click="num++">Next</button>
    <son1 @checks="getAns" :qnum="num"></son1>
    <son2 @checks="getAns" :qnum="num"></son2>
  </div>
</template>
<div id="app">
     <father></father>
</div>
<script>
// var eventBus=new Vue();
Vue.component('father', {
  template: '#question',
  data() {
    return {
      num: 1,
      rightAns: 'A',
      rightOne: '???',
    }
  },
  filters: {
    fmtNum(num) {
      return num < 10 ? '0' + num : num
    },
  },
  methods: {
    getAns(data) {
      console.log(data, 111)
      this.rightOne = data === 'A' ? 'U !' : '..,Ah-ha,not U'
    },
  },
  components: {
    son1: {
      props: ['qnum'],
      template: "<div>Jim's answer is {{answer}}<button @click='sendAns'>check</button> next {{qnum+1}}</div>",
      data() {
        return {
          answer: 'A',
          check: 'right',
        }
      },
      methods: {
        sendAns() {
          this.$emit('checks', this.answer) //eventBus.$emit(..)
        },
      },
    },
    son2: {
      props: ['qnum'],
      template: "<div>Pi's answer is {{answer}}<button @click='sendAns'>check</button> next {{qnum+1}}</div>",
      data() {
        return {
          answer: 'B',
          check: 'wrong',
        }
      },
      methods: {
        sendAns() {
          this.$emit('checks', this.answer) //eventBus.$emit(..)
        },
      },
    },
  },
})
new Vue({
  el: '#app',
})
</script>

在父组件模版中给子组件绑定自定义事件

发布者->订阅者
订阅者需要注册一个和发布者发布的消息相同的事件

父向子传值

  1. 父组件中定义好需要传递给子组件的数据
  2. 在父组件中使用子组件时,通过属性绑定的方式将定义好的数据传递过去,对于绑定的属性名不做任何要求
  3. 在子组件内部定义一个props的属性,这个属性通常是一个数组,数组中的字符串就是用来就收父组件传递过来的值 这个变量必须和父组件中使用子组件时绑定的属性同名

子向父传值

发布->订阅者模式

  1. 在子组件中定义好需要传递给父组件的数据
  2. 子组件内部根据业务需求触发this.$emit('自定义的事件名称','需要发送给父组件的数据this.info')
  3. 在父组件中使用子组件时绑定一个事件,事件名称和消息名称同名,同时事件处理函数要在父组件中定义好,子组件传过来的值就在事件处理函数的参数中

非父子组件传值需要借助一个中介,本质就是一个空的vue实例var bus = new Vue();
eventbus事件总线,使用一个公共的Vue实例作为中介,这个中介只负责数据的传输,不会挂载新的数据,需要传递数据的组件调用bus.$emit('消息名称','需要发布的数据')。需要接受数据的组件调用bus.$on('事件名称','事件处理函数'),事件名称和消息名称同名

<div id="app">
<father></father>
</div>
<script>
// 创建一个空的vue实例,作为事件总线
var eventbus = new Vue()
Vue.component('father', {
  template: `
          <div>
         <son></son>
         <daughter></daughter>
      </div>
    `,
  components: {
    son: {
      data() {
        return {
          mySisterName: '???',
        }
      },
      template: '<span>我妹妹告诉我她叫{{mySisterName}}</span>',
      mounted() {
        // 通过eventbus的$on()方法去监听兄弟节点发射过来的事件
        // $on有两个参数,一个是事件名称,一个是函数,该函数的默认值就是传递过来的数据
        eventbus.$on('tellBroMyName', (data) => {
          this.mySisterName = data
        })
      },
    },
    daughter: {
      data() {
        return {
          myName: '兰兰',
        }
      },
      template: '<button @click="emitMyName">点击就告诉哥哥我叫{{myName}}</button>',
      methods: {
        emitMyName() {
          // 通过事件总线发射一个事件名称和需要传递的数据
          eventbus.$emit('tellBroMyName', this.myName)
        },
      },
    },
  },
})
var vm = new Vue({
  el: '#app',
  data: {},
})
</script>

动态组件

<div id="app">
      <ul>
         <li><a href="javascript:;" @click="currentCom='index'">首页</a></li>
          <li><a href="javascript:;" @click="currentCom='productType'">蔬菜</a></li>
          <li><a href="javascript:;" @click="currentCom='productType'">水果</a></li>
          <li><a href="javascript:;" @click="currentCom='productType'">肉类</a></li>
      </ul>
      <component :is="currentCom"></component>
</div>
<script>
Vue.component('index', {
  template: '<div>首页</div>',
})
Vue.component('productType', {
  template: '<div>这里显示商品编号</div>',
})
new Vue({
  el: '#app',
  data: {
    currentCom: '',
  },
})
</script>

is属性和component实现组件切换,is指向哪个组件名则component就会被渲染成哪个组件

局部过滤器

不通过Vue.filter('xx',function(){..;return..})全局过滤器来创建,而是通过组件的filters:{ xx(a){..;return..} }创建局部的过滤器

组件生命周期

组件也是一个Vue实例,Vue实例其实就是一个组件,通常称作根组件 Vue实例会存在 初始化-运行中-销毁等多个阶段 这些阶段统称为Vue实例的生命周期,每一个阶段会对应的有一批钩子函数

初始化阶段
beforeCreate当 vue 实例一被创建就会执行,此时 vue 中的 data 和 methods 这些属性都还不存在
created当 vue 实例创建完毕后 data 中的数据和 methods 中的方法都挂载完毕后执行。数据的赋值和 ajax 请求通常都在 created 函数中执行
beforeMount当 DOM 挂载到页面时会自动执行,此时指令还没有被 vue 解析
mounted当 DOM 挂载到页面时会自动执行,所有指令都被 vue 解析。如果需要操作真实 DOM 则在 mounted 函数中进行
运行中阶段
beforeUpdate 当 data 中的数据发生变化时会自动执行,只是 data 中的数据发生了变化但还没有重新更新到 DOM 中
updated 当 data 中的数据发生变化时会自动执行,data 中的数据和视图中显示的数据都已经完全被修改了
销毁阶段
beforeDestroy vue 实例被销毁之前,当执行这个函数时 data 中的数据和 methods 中的方法还可以使用
destroyed vue 实例完全被销毁,当执行这个函数时 data 中的数据和 methods 中的方法都不可以使用了

构造函数:使用 new 关键字引导执行的函数叫做构造函数 回调函数:当一个函数作为参数进行传递时,这个函数称作回调函数 钩子函数:系统提前定义好的函数,会在适当的时机自动执行