Skip to content

Latest commit

 

History

History
258 lines (214 loc) · 6.81 KB

组件与单页组件.md

File metadata and controls

258 lines (214 loc) · 6.81 KB

组件与单页组件

上节中我们介绍了渲染的声明,但是我们在实际应用中我们需要拆分vue的功能使项目的结构更清晰以便于后续维护。于是我们需要使用组件,让一个功能分拆成多个组件,帮助我们细化功能让组件的功能更单一,并使相同功能在项目中能够复用。

学习本节你需要了解的内容:

  1. 箭头函数 arrow function

组件是vue中最为重要和强大的功能,我们可以把vue的应用想象成组件的集合。通过不同组件之间的组装和通信生成最终的应用。

生命周期钩子

组件也遵循vue的生命周期,我们可以通过在组件中监听对应生命周期事件来灵活控制组件,如:

<template>
    <div>{{hello}}</div>
</template>
<script>
    var data = { hello: 'Hello World' }
    setTimeout(function(){
        console.log('更新data值');
        data.hello='Hello New One';
    },1000)
    module.exports = {
        data(){
            return data
        },
        beforeUpdate(){
            console.log('显示新值',this.hello);
        }
    }
</script>

如上组件,我们通过监听beforeUpdate来查看改变的hello值。

打印数据依次为:

更新data值
显示新值 Hello New One

组件间的交互

在vue 2.0中提供了两种方式进行组件的交互:1.属性,2.事件,两者的关系如下图所示:

属性

Vue.component('child', {
  // declare the props
  props: ['message'],
  // just like data, the prop can be used inside templates
  // and is also made available in the vm as this.message
  template: '<span>{{ message }}</span>'
})
<child message="hello!"></child>

如上方官方文档所示,组件可以接收静态数据并展示,如下的形式也可以接收动态数据:

<child :my-message="parentMsg"></child>

此时child接收的属性名是myMessage

在组件内还可以定义属性验证,来严格规范组件传入属性。

Vue.component('example', {
  props: {
    // basic type check (`null` means accept any type)
    propA: Number,
    // multiple possible types
    propB: [String, Number],
    // a required string
    propC: {
      type: String,
      required: true
    },
    // a number with default value
    propD: {
      type: Number,
      default: 100
    },
    // object/array defaults should be returned from a
    // factory function
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // custom validator function
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})
  • 属性遵循单向数据流模式,当父组件的值变更,则子组件的值也会对应变更,但子组件data的变更并不会影响父组件。
  • 请查看官方文档了解更多

事件

在组件中,我们也可以使用v-on传递一个自定义事件,并使用 this.$emit 发起事件,第一个参数时事件名,后续参数同步传输到自定义事件的参数中,如下的官方DEMO:

<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
Vue.component('button-counter', {
  template: '<button v-on:click="increment">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    increment: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})

数据计算与监听

所有传入的数据不仅可以在数据绑定时用过滤器,还可以使用计算函数动态计算值,如下所示:

var vm = new Vue({
  data: { a: 1 },
  computed: {
    // get only, just need a function
    aDouble: function () {
      return this.a * 2
    },
    // both get and set
    aPlus: {
      get: function () {
        return this.a + 1
      },
      set: function (v) {
        this.a = v - 1
      }
    }
  }
})
vm.aPlus   // -> 2
vm.aPlus = 3
vm.a       // -> 2
vm.aDouble // -> 4
  • 注意,这里的计算属性如果使用复杂结构的object数据有可能产生内存泄露,建议使用Object.assign深复制。
  • 计算属性如果动态计算列表时,注意列表的处理。参见“列表渲染”部分内容。

同时,还可以使用watch来监听函数的变化,处理对应的操作(比如移动端经常通过检测列表变动来更新Iscroll的高度),如下:

var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: 3
  },
  watch: {
    a: function (val, oldVal) {
      console.log('new: %s, old: %s', val, oldVal)
    },
    // string method name
    b: 'someMethod',
    // deep watcher
    c: {
      handler: function (val, oldVal) { /* ... */ },
      deep: true
    }
  }
})
vm.a = 2 // -> new: 2, old: 1

单页组件

为了保证项目的可维护性,我们引入了vue在webpack的加载器vue-loader(之前在webpack中已声明),通过vue-loader我们可以解析.vue的文件为vue组件,一个完整的vue组件由HTML和js两部分构成,如下:

<template>
    <div>
        <template v-if="hello">{{hello}}</template>
        <p><a @click.prevent="msgBack">Send a msg</a></p>
    </div>
</template>
<script>
    var data = { hello: 'Hello World' }
    module.exports = {
        data(){
            return data
        },
        methods:{
            msgBack:function(){
                this.hello='I get your msg';
            }
        }
    }
</script>

和nodejs的模块原理一样,每个vue组件都会被打包为一个模块。现在我们来改造一下app.js载入插件。

import Vue from 'Vue'; //载入vue
import Hello from './components/hello.vue'; //载入hello组件

var vm = new Vue({
  el:'#render', //根节点
  render:createElement=>createElement(Hello)
});

现在webpack重新生成,就可以使用我们更加健壮的项目了。

在后续的示例中,我们通过根组件引入子组件来扩展更多的应用场景,这也是vue-router的开发思路。