HTTP/1.1 200 OK Date: Tue, 19 Feb 2019 21:10:35 GMT Content-Type: text/html Server: Microsoft-IIS/7.5 X-Powered-By: jb51.net Content-Length: 61536 X-Via: 1.1 VMxgHK4ph48:5 (Cdn Cache Server V2.0), 1.1 PSgdhzdx7oi97:10 (Cdn Cache Server V2.0), 1.1 PSxgHK6zh72:3 (Cdn Cache Server V2.0) Connection: keep-alive Vue组件的使用及个人理解与介绍_vue.js_脚本之家

Vue组件的使用及个人理解与介绍

 更新时间:2019年02月09日 14:35:56   投稿:wdc   我要评论

本文介绍了VUE中组件的基本使用以及个人对VUE组件的理解,希望能帮助到大家

组件的基本使用

注册组件

注册组件就是利用Vue.component()方法,先传入一个自定义组件的名字,然后传入这个组件的配置。

 Vue.component('mycomponent',{
  template: `<div>这是一个自定义组件</div>`,
  data () {
   return {
    message: 'hello world'
   }
  }
 })

如上方式,就已经创建了一个自定义组件,然后就可以在Vue实例挂在的DOM元素中使用它。

 <div id="app">
  <mycomponent></mycomponent>
  <my-component></my-component>
</div>
<script>
 var app = new Vue({
  el: '#app',
  data: {
  },
  components: {
   'my-component': {
    template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>`,
   }
  }
 })
</script>

直接使用Vue.component()创建的组件,所有的Vue实例都可以使用。还可以在某个Vue实例中注册只有自己能使用的组件。

var app = new Vue({
  el: '#app',
  data: {
  },
  components: {
   'my-component': {
    template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>`,
   }
  }
 })

模板的要求

注意:组件的模板只能有一个根元素。下面的情况是不允许的。

template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>
      <button>hello</button>`,

组件中的data必须是函数

可以看出,注册组件时传入的配置和创建Vue实例差不多,但也有不同,其中一个就是data属性必须是一个函数。
这是因为如果像Vue实例那样,传入一个对象,由于JS中对象类型的变量实际上保存的是对象的引用,所以当存在多个这样的组件时,会共享数据,导致一个组件中数据的改变会引起其他组件数据的改变。

而使用一个返回对象的函数,每次使用组件都会创建一个新的对象,这样就不会出现共享数据的问题来了。

关于DOM模板的解析

当使用 DOM 作为模版时 (例如,将 el 选项挂载到一个已存在的元素上), 你会受到 HTML 的一些限制,因为 Vue 只有在浏览器解析和标准化 HTML 后才能获取模板内容。尤其像这些元素 <ul>,<ol>,<table>,<select> 限制了能被它包裹的元素,而一些像 <option> 这样的元素只能出现在某些其它元素内部。

在自定义组件中使用这些受限制的元素时会导致一些问题,例如:

<table>
 <my-row>...</my-row>
</table>

自定义组件 <my-row> 被认为是无效的内容,因此在渲染的时候会导致错误。这时应使用特殊的 is 属性:

<table>
 <tr is="my-row"></tr>
</table>

也就是说,标准HTML中,一些元素中只能放置特定的子元素,另一些元素只能存在于特定的父元素中。比如table中不能放置div,tr的父元素不能div等。所以,当使用自定义标签时,标签名还是那些标签的名字,但是可以在标签的is属性中填写自定义组件的名字。

应当注意,如果您使用来自以下来源之一的字符串模板,这些限制将不适用:

<script type="text/x-template">
JavaScript 内联模版字符串
.vue 组件
其中,前两个模板都不是Vue官方推荐的,所以一般情况下,只有单文件组件.vue可以忽略这种情况。

组件的属性和事件

在html中使用元素,会有一些属性,如class,id,还可以绑定事件,自定义组件也是可以的。当在一个组件中,使用了其他自定义组件时,就会利用子组件的属性和事件来和父组件进行数据交流。
<img src="/assets/images/props-events.png"/>

如上如所示,父子组件之间的通信就是 props down,events up,父组件通过 属性props向下传递数据给子组件,子组件通过 事件events 给父组件发送消息。
比如,子组件需要某个数据,就在内部定义一个prop属性,然后父组件就像给html元素指定特性值一样,把自己的data属性传递给子组件的这个属性。
而当子组件内部发生了什么事情的时候,就通过自定义事件来把这个事情涉及到的数据暴露出来,供父组件处理。

<my-component v-bind:foo="baz" v-on:event-a="doThis(arg1,...arg2)"></my-component>

如上代码,

foo是<my-component>组件内部定义的一个prop属性,baz是父组件的一个data属性,
event-a是子组件定义的一个事件,doThis是父组件的一个方法
过程就是这样:

父组件把baz数据通过prop传递给子组件的foo;
子组件内部得到foo的值,就可以进行相应的操作;
当子组件内部发生了一些变化,希望父组件能知道时,就利用代码触发event-a事件,把一些数据发送出去
父组件把这个事件处理器绑定为doThis方法,子组件发送的数据,就作为doThis方法的参数被传进来
然后父组件就可以根据这些数据,进行相应的操作

属性Props

Vue组件通过props属性来声明一个自己的属性,然后父组件就可以往里面传递数据。

Vue.component('mycomponent',{
  template: '<div>这是一个自定义组件,父组件传给我的内容是:{{myMessage}}</div>',
  props: ['myMessage'],
  data () {
   return {
    message: 'hello world'
   }
  }
 })

然后调用该组件

<div id="app">
  <mycomponent my-message="hello"></mycomponent>
</div>

注意,由于HTML特性是不区分大小写的,所以传递属性值时,myMessage应该转换成 kebab-case (短横线隔开式)my-message="hello"。

v-bind绑定属性值
这里说一下v-bind绑定属性值的一个特性:一般情况下,使用v-bind给元素特性(attribute)传递值时,Vue会将""中的内容当做一个表达式。
比如:

<div attr="message">hello</div>

上面这样,div元素的attr特性值就是message。

而这样

<div v-bind:attr="message">hello</div>

这里的message应该是Vue实例的data的一个属性,这样div元素的attr特性值就是message这个属性的值。

之所以说是一般情况,是因为class和style特性并不是这样。用v-bind:class和class传入正常的类名,效果是一样的,因为对于这两个特性,Vue采用了合并而不是替换的原则。

动态绑定特性值

根据上面,想要把父组件的属性绑定到子组件,应该使用v-bind,这样,父组件中数据改变时能反映到子组件。
注意,根据父组件传递给子组件的属性类型的不同,当在子组件中更改这个属性时,会有以下两种情况:

当父组件传递的属性是引用类型时,在子组件中更改相应的属性会导致父组件相应属性的更改。

  <div id="app2">
   <div>这是父组件的parentArray:{{parentArray}}</div>
   <my-component :child-array="parentArray"></my-component>
  </div>
  <script>
   Vue.component('my-component', {
    template: `
    <div>这是接收了父组件传递值的子组件的childArray: {{childArray}} <br>
      <button type="button" @click="changeArray">
      点击我改变父元素的parentArray</button>
     </div>`,
    props: ['childArray'],
    data () {
     return {
      counter: 1
     }
    },
    methods: {
     changeArray () {
      this.childArray.push(this.counter++)
     }
    }
   })
   new Vue({
    el: '#app2',
    data: {
     parentArray: []
    }
   })
  </script>

当父组件传递值为基本类型时,在子组件中更改这个属性会报错。正确的做法是,在父组件中绑定属性值时,加上.sync修饰符。

<my-component :child-array.sync="parentArray"></my-component>

然后在子组件中改变相应的属性

  methods: {
   changeArray () {
    this.counter++
    this.$emit('update:childArray', this.counter)
   }
  }

子组件希望对传入的prop进行操作

一般来说,是不建议在子组件中对父组件中传递来的属性进行操作的。如果真的有这种需求,可以这样:

父组件传递了一个基本类型值,那么可以在子组件中创建一个新的属性,并以传递进来的值进行初始化,之后就可以操作这个新的属性了

props: ['initialCounter'],
data: function () {
 return { counter: this.initialCounter }
}

父组件传递了一个引用类型值,为了避免更改父组件中相应的数据,最好是对引用类型进行复制。复杂的情况,肯定应该是深复制。

给子组件传递正确类型的值

同样是上面的原因,静态的给子组件的特性传递值,它都会把他当做一个字符串。

<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>

子组件中,特性的值是字符串 "1" 而不是 number 1。如果想传递正确的数值,应该使用v-bind传递,这样就能把传递的值当做一个表达式来处理,而不是字符串。

<!-- 传递实际的 number 1 -->
<comp v-bind:some-prop="1"></comp>

Prop验证

我们可以给组件的props属性添加验证,当传入的数据不符合要求时,Vue会发出警告。

Vue.component('example', {
 props: {
  // 基础类型检测 (`null` 意思是任何类型都可以)
  propA: Number,
  // 多种类型
  propB: [String, Number],
  // 必传且是字符串
  propC: {
   type: String,
   required: true
  },
  // 数字,有默认值
  propD: {
   type: Number,
   default: 100
  },
  // 数组/对象的默认值应当由一个工厂函数返回
  propE: {
   type: Object,
   default: function () {
    return { message: 'hello' }
   }
  },
  // 自定义验证函数
  propF: {
   validator: function (value) {
    return value > 10
   }
  }
 }
})

type 可以是下面原生构造器:

String
Number
Boolean
Function
Object
Array
Symbol
type 也可以是一个自定义构造器函数,使用 instanceof 检测。

 // 自定义Person构造器
 function Person(name, age) {
  this.name = name
  this.age = age
 }
 Vue.component('my-component', {
  template: `<div>名字: {{ person-prop.name }}, 年龄: {{ person-prop.age }} </div>`,
  props: {
   person-prop: {
    type: Person   // 指定类型
   }
  }
 })
 new Vue({
  el: '#app2',
  data: {
   person: 2    // 传入Number类型会报错
  }
 })

非Prop类型的属性

也可以像在html标签中添加data-开头的自定义属性一样,给自定义组件添加任意的属性。而不仅限于data-*形式,这样做的话,Vue会把这个属性放在自定义组件的根元素上。一个自定义组件的模板只能有一个根元素。

覆盖非Prop属性

如果父组件向子组件的非prop属性传递了值,那么这个值会覆盖子组件模板中的特性。

<div id="app3">
  <my-component2 att="helloParent"></my-component2>
</div>