# 组件
组件简介 组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。
# 组件注册
# 全局注册
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
<div id="app">
<com></com>
</div>
<script>
// 全局组件
Vue.component("com", {
data() {
return {
num: 10,
};
},
template: "<h2>{{ num }}</h2>",
});
var vm = new Vue({
el: "#app",
});
</script>
# 局部注册
只能在当前页面中使用
<div id="app">
<com></com>
<com1></com1>
</div>
<script>
// 局部注册组件
var vm = new Vue({
el: "#app",
components: {
com: {
data() {
return {
info: "我是局部注册的组件",
};
},
template: "<h3>{{ info }}</h3>",
},
com1: {
data() {
return {
info: "我是局部注册1的组件",
};
},
template: "<h3>{{ info }}</h3>",
},
},
});
</script>
# 组件的大小写问题
在 dom 里面是不识别大写的 浏览器会把标签中的大写转换成小写 如果要识别的话需要用-连接 如
<div id="app">
<h2>标题</h2>
<is-show></is-show>
</div>
<script>
// 局部注册组件
var vm = new Vue({
el: "#app",
components: {
isShow: {
data() {
return {
info: "我是局部注册的组件",
};
},
template: "<h3>{{ info }}</h3>",
},
},
});
</script>
在页面里面就会渲染成
# 组件的特点
- data 必须是一个函数
- 组件是密封的 组件之间的数据是相互独立的 也就是说即使写几个组件 更改其中的某一个组件之间的值 其他的组件也不会受到影响
- 组件模板中只能有一个根元素
- 组件传值 组件是密封的 所有想给某个组件传值 vue 提供了 props 通过 props 传值 这个 props 是写在我们组件里面的一个属性 传值通过这个属性来传值的
<div id="app">
<is-show prop1="父组件传递的数据" :parinfo="parinfo"></is-show>
</div>
<script>
// 局部注册组件
var vm = new Vue({
el: "#app",
data() {
return {
parinfo: "我是父组件的数据",
};
},
components: {
"is-show": {
props: ["prop1", "parinfo"],
data() {
return {
info: "我是局部注册的组件",
};
},
template: "<h3>{{ info }} {{ prop1 }} {{ parinfo }}</h3>",
},
},
});
</script>
# props 类型检测
props 类型 有八种类型作用就是对我们传递的数据进行类型检查 还会在传递数据类型遇到错误的时候从浏览器的 JavaScript 控制台提示用户
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
<script>
var vm = new Vue({
el: "#app",
components: {
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise, // or any other constructor
},
},
});
</script>
# 组件传递数据的三种方式
# 父元素传值到子元素
通过 props 传值
传值注意事项
单向数据流 父级 prop 的更新会向下流动到子组件中,但是反过来则不行 如果我们实在想改变这个传值 我们用 data 或者计算属性来代替这个传值
<div id="app">
<is-show :parinfo="parinfo"></is-show>
</div>
<script>
var vm = new Vue({
el: "#app",
data() {
return {
parinfo: true,
};
},
components: {
"is-show": {
props: {
parinfo: Boolean,
},
data() {
return {
info: "我是局部注册的组件",
infos: this.parinfo,
};
},
methods: {
changeParent() {
this.infos = !this.infos;
},
},
template: `<div>
<h3> {{ infos }}</h3>
<button @click="changeParent">改变父元素传值</button>
</div>`,
},
},
});
</script>
# 子组件向父元素传递值
子组件向父元素传递值是通过自定义事件来完成的
- 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
- 父组件将方法的引用传递给子组件,其中,getMsg 是父组件中 methods 中定义的方法名称,func 是子组件调用传递过来方法时候的方法名称
<son @func="getMsg"></son>
- 子组件内部通过 this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app">
<!-- 引用父组件 -->
<son @func="getMsg"></son>
<!-- 组件模板定义 -->
<script type="x-template" id="son">
<div>
<input type="button" value="向父组件传值" @click="sendMsg" />
</div>
</script>
</div>
<script>
// 子组件的定义方式
Vue.component("son", {
template: "#son", // 组件模板Id
methods: {
sendMsg() {
// 按钮的点击事件
this.$emit("func", "OK"); // 调用父组件传递过来的方法,同时把数据传递出去
},
},
});
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: "#app",
data: {},
methods: {
getMsg(val) {
// 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义
alert(val);
},
},
});
</script>
# 非父子组件传值
非父子组件之间传值,需要定义个bus
,作为中间仓库来传值,不然路由组件之间达不到传值的效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app">
<zujian1 :mes="childInfo"></zujian1>
<zujian2 @event="parEvents"></zujian2>
</div>
<script>
// 局部注册组件 bus
var bus = new Vue();
var vm = new Vue({
el: "#app",
data() {
return {
parinfo: "我是父组件的数据",
childInfo: "",
};
},
methods: {
parEvents(val) {
this.childInfo = val;
console.log("我是子组件传递过来的数据", val);
},
},
components: {
zujian1: {
props: ["mes"],
data() {
return {
get1: "",
};
},
created() {
var that = this;
var mess = bus.$on("busevent", (val) => {
console.log(that, this);
this.get1 = val;
//return val
});
},
template: "<h3>组件 传递过来的值是{{ mes }} {{ get1 }}</h3>",
},
zujian2: {
data() {
return {};
},
methods: {
post2() {
//this.$emit("event",1)
bus.$emit("busevent", 1);
},
},
template: "<h3 @click='post2'>组件2传递数据</h3>",
},
},
});
</script>
</body>
</html>
# sync 修饰符
在 vue 的组件通信 props 中,一般情况下,数据都是单向的,即父组件数据的更改会下传到子组件(用了.once 除外),子组件对数据无法做出更改(当传递的数据是引用数据类型时,可以更改父组件数据,比如,数组的破坏性方法,push 等)。sync 可以实现数据的双向绑定
示例代码如下
<comp :foo.sync="bar"></comp>
会被扩展为
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
完整示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="lib/vue.js"></script>
</head>
<body>
<div id="app">
<com :message.sync="mes"></com>
</div>
<script>
var vm = new Vue({
el: "#app",
methods: {},
data() {
return {
mes: "父元素里面的值",
};
},
components: {
com: {
props: ["message"],
template: "<h3 @click='changeProp'>子组件 {{message}}</h3>",
methods: {
changeProp() {
this.$emit("update:message", "改变之后的");
},
},
},
},
});
</script>
</body>
</html>