在谈论 Vue 的组件化开发 时,我们已经提到过,组件有两种:普通组件和单文件组件。
普通组件的缺点:
- html 代码是作为 js 的字符串进行编写,所以组装和开发的时候不易理解,而且没有高亮效果。
- 普通组件用在小项目中非常合适,但是复杂的大项目中,如果把更多的组件放在 html 文件中,那么维护成本就会变得非常昂贵。
- 普通组件只是整合了 js 和 html,但是 css 代码被剥离出去了。使用的时候的时候不好处理。
将一个组件相关的 html 结构,css 样式,以及交互的 JavaScript 代码从 html 文件中剥离出来,合成一个文件,这个文件就是单文件组件。相当于一个组件具有了结构、表现和行为的完整功能,方便组件之间随意组合以及组件的重用,这种文件的扩展名为“.vue”,比如:”Home.vue”。
在组件文件中通常有三个标签,分别用来编写视图、vm 对象(js 代码)和 css 样式代码。
template 编写 html 代码
1 | <template> |
script 编写 vue.js 代码
1 | <script> |
style 编写当前组件的样式代码
1 | <style scoped> /* 这里的scoped的含义为,样式效果仅对当前vue文件组件有效 */ |
完成案例:点击加减数字
创建 Homes.vue
1 | <template> |
在 App.vue
组件中调用上面的组件
1 | <template> |
在开发 vue 项目之前,需要手动把 App.vue
的 HelloWorld 组件代码以及默认的 css 样式清除掉。
上面的代码效果:
组件的嵌套
有时候开发 vue 项目时,页面也可以算是一个大组件,同时页面也可以分成多个子组件。
这就会产生父组件调用子组件的情况。例如,我们可以声明一个组件 Home.vue
作为父组件。
在 components/ 下创建一个保存子组件的目录 HomeSon。
在 HomeSon 目录下,可以创建当前页面的子组件。例如,Menu.vue
。
1 | // 组件中代码必须写在同一个标签中 |
然后,在父组件中调用上面声明的子组件。
最后,父组件被 App.vue
调用。就可以看到页面效果。
效果:
传递数据
父组件的数据传递给子组件
例如,我们希望把父组件的数据传递给子组件.
可以通过 props 属性来进行数据传递.
传递数据三个步骤:
在父组件中,调用子组件的组名处,使用属性值的方式往下传递数据
1
<Menu :mynum="num" title="home里面写的数据"/>
上面的例子展示了在父组件调用 Menu 子组件的时候传递数据可以是变量和普通字符串两种形式:
- 如果要传递变量(变量可以各种类型的数据),属性名左边必须加上冒号
:
。同时,属性名是自定义的,会在子组件中使用 - 如果要传递普通字符串数据,则不需要加上冒号
- 如果要传递变量(变量可以各种类型的数据),属性名左边必须加上冒号
在子组件中接受上面父组件传递的数据,需要在 vm 组件对象中,使用 props 属性类接受。
1
2
3
4
5
6
7
8
9
10
11<script>
export default {
name:"Menu",
props:["mynum","title"], // 这里接收了两个数据
data: function(){
return {
msg:"这是Menu组件里面的菜单",
}
}
}
</script>在子组件中的 template 中使用父组件传递过来的数据。
1
2
3
4
5
6<template>
<div id="menu">
<span>{{msg}},{{title}}</span>
<div>hello,{{mynum}}</div>
</div>
</template>
效果:
步骤流程:
使用父组件传递数据给子组件时,需要注意以下几点:
如果传递的数据是变量,则需要在属性左边添加冒号
传递数据是变量,这种数据称之为“动态数据传递”
传递数据不是变量,这种数据称之为“静态数据传递”
父组件中修改了数据,在子组件中会被同步修改。但是子组件中的数据修改了,是不是影响到父组件中的数据的。这种情况在开发时也被称为“单向数据流”
子组件传递数据给父组件
在子组件中,通过
this.$emit()
来调用父组件中定义的事件.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<template>
<div>
<p>Post的子组件</p>
<h2>{{fnum}}</h2>
<p>data={{data}}</p>
<p>fnum={{fnum}}</p>
<div><input type="text" v-model="fnum"></div>
</div>
</template>
<script>
export default {
name: "PostSon",
// 父组件传递数据给子组件: 1. 在父组件中调用子组件的组件名称标签上面声明属性和传递值,2. 在子组件中通过props进行接收
props:["data","fnum"], // 接受父组件中传递过来的数据
// 子组件传递数据给父组件[事件的方式进行传递]:
watch:{
fnum(){
console.log(this.fnum);
// this.$emit("父元素的自定义事件","要传递的数据"); // 通过this.$emit()方法,子组件可以把数据传递给父组件
this.$emit("postparentdata",this.fnum);
}
}
}
</script>
<style scoped>
</style>父组件中声明一个和子组件中
this.$emit("自定义事件名称")
对应的事件属性。1
2
3
4
5
6<template>
<div>
<h1>num={{num}}</h1>
<Son data="我是父组件里面的内容" :fnum="num" @postparentdata="getsondata"></Son>
</div>
</template>父组件中声明一个自定义方法,在自定义事件被调用时执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<script>
import Son from "./PostSon"
export default {
name: "Post",
data(){
return {
num: 100,
}
},
components:{
Son:Son,
},
methods:{
getsondata(message){
console.log("父组件"+message);
this.num = message;
}
}
}
</script>