前言

本篇将主要介绍Vue组件的相关内容,有些可能会较为简略

部分内容参考菜鸟教程Vue.js 入门教程 | 菜鸟教程 (runoob.com)和Vue的官方文档介绍 | Vue.js (vuejs.org),另外参考书籍梁灏,Vue.js实战[M] 北京:清华大学出版社,2017

注:由于个人能力有限,暂不会在Markdown中使用Vue相关内容

所以另外写了一个网页,作为效果参考。链接如下

https://www.226yzy.com/demos/VueDemo/

基本示例

一个简单的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app0">
<hallo-world></hallo-world>
<hallo-world></hallo-world>
<hallo-world></hallo-world>
</div>

<script>
// 全局注册
Vue.component('hallo-world', {
//内容
template: '<button>Hello World</button>'
})
// 创建根实例
new Vue({
el: '#app0'
})
</script>

通过得出的效果可知,组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

函数示例

上面没有啥数据绑定和事件响应,所以增加了下面的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app0-1">
<hallo-world></hallo-world>
<hallo-world></hallo-world>
<hallo-world></hallo-world>
</div>

<script>
// 全局注册
Vue.component('hallo-world', {
template: '<button @click="x++">你点击了这个 {{x}} 次</button>',
data:function(){
return {
x:0
}
}
})
// 创建根实例
new Vue({
el: '#app0-1'
})
</script>

当点击按钮时,每个组件都会各自独立维护它的 x。因为你每用一次组件,就会有一个它的新实例被创建。

另外,当我们定义这个 <hello-world/> 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象

1
2
3
data: {
x: 0
}

在组件中data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

1
2
3
4
5
data: function () {
return {
x: 0
}
}

如果你使用的是对象,请用以下代码试试会发生什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="app0-1-1">
<hallo-world></hallo-world>
<hallo-world></hallo-world>
<hallo-world></hallo-world>
</div>

<script>
var t={
x:0
}
// 全局注册
Vue.component('hallo-world', {
template: '<button @click="x++">你点击了这个 {{x}} 次</button>',
data: function () {
return t
}
})
// 创建根实例
new Vue({
el: '#app0-1-1',
})
</script>

上面代码产生的效果是:点击一个按钮就会影响到其它按钮

本例中的template

template中,一般写成单行,否则会报错

如果要多行,那么可以在需要换行的那一行后面添加转义字符\

对上一个代码换行修改示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app0-1-0">
<hallo-world></hallo-world>
<hallo-world></hallo-world>
<hallo-world></hallo-world>
</div>

<script>
// 全局注册
Vue.component('hallo-world', {
template: '<button @click="x++">\
你点击了这个 {{x}} 次\
</button>',
data: function () {
return {
x: 0
}
}
})
// 创建根实例
new Vue({
el: '#app0-1-0'
})
</script>

全局组件

所有实例都能用全局组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app0-1">
<hallo-world></hallo-world>
<hallo-world></hallo-world>
<hallo-world></hallo-world>
</div>

<script>
// 全局注册
Vue.component('hallo-world', {
template: '<button @click="x++">你点击了这个 {{x}} 次</button>',
data:function(){
return {
x:0
}
}
})
// 创建根实例
new Vue({
el: '#app0-1'
})
</script>

这个代码跟基本示例中的代码基本一样

局部组件

我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app0-2">
<runoob></runoob>
</div>

<script>
var Child = {
template: '<h1>自定义组件!</h1>'
}

// 创建根实例
new Vue({
el: '#app0-2',
components: {
// <runoob> 将只在父模板可用
'runoob': Child
}
})
</script>

prop

通过 Prop 向子组件传递数据

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。(也就是向组件传入数据)

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 prop

1
<div id="app0-3">            <child message="hello!"></child>        </div>        <script>            // 注册            Vue.component('child', {                // 声明 props                props: ['message'],                // 同样也可以在 vm 实例中像 "this.message" 这样使用                template: '<span>{{ message }}</span>'            })            // 创建根实例            new Vue({                el: '#app0-3'            })        </script>

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在组件实例中访问这个值,就像访问 data 中的值一样。

Prop 的大小写

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

示例如下

1
<div id="app0-3-1">            <blog-post post-title="hello!"></blog-post>        </div>        <script>            // 全局注册            Vue.component('blog-post', {                // 在 JavaScript 中是 camelCase 的                props: ['postTitle'],                template: '<h3>{{ postTitle }}</h3>'            })            // 创建根实例            new Vue({                el: '#app0-3-1'            })        </script>

监听子组件事件

参考自菜鸟教程

我们可以使用 v-on绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

另外,父组件可以在使用子组件的地方直接用 v-on来监听子组件触发的事件。

下面示例来自菜鸟教程

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

自定义组件的 v-model

参考自菜鸟教程

组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。

1
<input v-model="parentData">

等价于:

1
<input     :value="parentData"    @input="parentData = $event.target.value">

参考文献

在线资源

菜鸟教程

Vue.js 入门教程 | 菜鸟教程 (runoob.com)

Vue官方中文文档

介绍 | Vue.js (vuejs.org)

其他博客

Vue快速入门_成都往右的博客-CSDN博客_vue入门

参考书籍

[1]梁灏,Vue.js实战[M] 北京:清华大学出版社,2017

其他

部分内容来自姚军老师的上课内容