好处:
全局组件:
注册全局组件 ,可以用横杠也可用驼峰,如myButton / my-button,但使用时,只支持横杠
Vue.component('my-button', {
template: '{{msg}}', //template设置组件中的内容
data() { //组件中的data是个函数,它返回对象,与实例中的data不同,那个值是一个对象
return {
msg: 'aaa'
}
}
})
使用全局组件:
<div id="app">
<!-- 使用全局组件 ,在DOM中只支持-的写法my-button -->
<my-button></my-button>
</div>
局部组件:是在实例内部写的。
let vm = new Vue({
// template: '1111', //Vue实例中也有template,若在实例中发现直接渲染,没有就会渲染挂载的Vue实例
el: '#app',
data: {},
// 局部组件:在实例中 一般不这么写,写太多会不好维护
components: {
'my-button': {
template: '{{msg}}', //设置组件中的内容
data() { //组件的data是个函数,返回一个对象
return {
msg: '局部组件bbb'
}
}
}
}
})
通常这么写:
<!-- //组件的三步骤:1. 定义组件;2.注册组件;3.使用组件 -->
// 1.定义组件
let myButton = {
template: '{{msg}}', //设置组件中的内容
data() { //组件的data是个函数,返回一个对象
return {
msg: '局部组件bbb'
}
}
}
let vm = new Vue({
el: '#app',
data: {},
// 局部组件:在实例中
components: {
//2.注册组件,可以简写myButton,ES6写法
myButton: myButton
}
})
// dom中相应位置使用组件:
<div id="app">
<!-- 使用全局组件 ,在dom中只支持横杠写法 my-button -->
<!-- 3.使用组件 -->
<my-button></my-button>
</div>
若在组件的template中,有很多div,以及有很多的层级,有点繁琐且不美观,可以使用下面这个写法:
<body>
<div id="app">
<!-- 3.使用组件 -->
<my-button></my-button>
</div>
<template id="button">
<div>{{msg}}</div>
</template>
</body>
把组件中的内容,在dom中定义一个id名为button的template,然后在写组件时,这么写:
let myButton = {
// template: '{{msg}}', //设置组件中的内容
template: '#button', //设置组件中的内容,如果有很多的代码,写到这里太繁琐,可以在dom中写一个template,命名一个id,将组件中的内容都放到template中,在这使用时直接写上id
data() { //组件的data是个函数,返回一个对象
return {
msg: '局部组件bbb'
}
}
}
若有多个组件,也是如此写:先定义,再注册,最后使用
// 定义组件:
let hello = {
template: '#hello'
}
// dom中的:
<template id="hello">
<div>hello</div>
</template>
// 注册组件:
components: {
myButton, //2.注册组件,myButton: myButton可以简写myButton,ES6写法
hello
}
// 使用组件:
<div id="app">
<!-- 3.使用组件 -->
<my-button></my-button>
<hello></hello>
</div>
此时myButton与hello是兄弟组件的关系,若想变成父子,也是可以的,注册的时候放到myButton组件components中,使用的时候也在myButton的dom中使用
// 1.定义组件
let hello = { //在调用前要定义,因let定义的变量不会提升
template: '#hello'
}
// 2.注册组件
let myButton = {
template: '#button',
data() {
return {
msg: '局部组件bbb'
}
},
//每个组件中都有components,里面放的是它的子组件
components: {
hello //使用组件的时候要放到父组件中,hello是mybutton的一个子组件
}
}
// 3.使用组件
//
<template id="button">
<div>
{{msg}}
<hello></hello>
</div>
</template>
npm install -g @vue/cli
npm install -g @vue/cli-service-global
开发环境:vue serve App.vue
生产环境:vue build App.vue
<template>
<div>
Parent
<!-- m="500"是静态的字符串,若是要传动态的使用:m -->
<!-- 父组件监听子组件的事件,并给事件绑定函数 -->
<!-- <Son :m="money" @change="fn"></Son> -->
<!-- 父子传递数据,语法糖的写法 -->
<!-- <Son :m.sync="money"></Son>-->
<!-- v-model的原理是把money绑定在属性value中 绑定的事件名@input -->
<!-- <Son :value="money" @input="(data)=>money=data"></Son> -->
<Son v-model="money"></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
data() {
return {
// money: 'ABC',
money: 500,
};
},
components: {
Son
},
// 父组件中的绑定事件执行
methods: {
fn(data) {
// 当父组件监听到子组件的点击事件执行了,绑定方法就执行,并且会拿到子组件对应传过来的值
this.money = data;
}
}
};
</script>
子组件:
<template>
<div>
Son
<!-- 获取传过来的值用这个 -->
<!-- {{m}} -->
<!-- 这是改变后的值 -->
{{changeM}}
<button @click="giveData">给父组件数据</button>
<!--这是v-model对应的值value -->
{{value}}
</div>
</template>
<script>
export default {
// props: ["m"], //获取从父组件拿到的值使用,props
// computed: {
// //若想对传过来的值修改,例如变成小写的,推荐使用计算属性
// changeM() {
// return this.m.trim().toLowerCase();
// }
// },
// 验证传过来的值,下面会详解
props: {
m: {
type: [String, Number] //值的类型
// default: 100 //默认值 , 它与required不能同时使用,用一个就可以
// required: true //必传
// validator: value => {
// //自定义验证规则
// return value > 400 && value < 1000;
// }
},
arr: {
type: Array, //若是数组或对象,默认值是函数
default: () => [1]
},
obj: {
type: Object,
default: () => ({}) //ES6中,函数中的直接写{}是作用域,所以需要加()
},
value: {
//这是v-model对应的value
type: Number
}
},
computed: { //若想对传过来的值修改,推荐使用计算属性
changeM() {
return this.m.trim().toLowerCase();
}
},
//
methods: {
giveData() {
// 子组件执行父组件监听的事件,子组件使用$emit将数据发送给父组件
// this.$emit("change", 999); //change是监听的事件,999是参数
// this.$emit("update:m", 999); //若在父组件使用:m.sync='money',在这要使用update带属性名表示事件
this.$emit("input", 999); //使用v=model传的值,事件是input事件
}
}
};
</script>
父组件传的值为:
data() {
return {
money: 400,
};
},//控制台会报错,自定义验证规则失败,因不满足条件
子组件:
<template>
<div>
Son
<!-- 获取传过来的值用这个 -->
{{m}}
</div>
</template>
<script>
export default {
// 验证传过来的值
props:{
m:{
type:[String,Number], //值的类型
// default:100, //默认值 , 它与required不能同时使用,用一个就可以
required:true, //必传
validator:(value)=>{ //自定义验证规则
return value>400 && value<1000
}
}
},
};
</script>
若传的值是一个对象或数组(空数组,或空对象),可以设置默认值,需要注意:
数组的话,默认值是一个函数。
props:{
arr: {
type: Array, //若是数组或对象,默认值是函数
default: () => [1]
},
obj: {
type: Object,
default: () => ({}) //ES6中,函数中的直接写{}是作用域,所以需要加()
}
}
<template>
<div>
Parent
<!-- m="500"是静态的字符串,若是要传动态的使用:m -->
<!-- 父组件监听子组件的事件,并给事件绑定函数 -->
<!-- <Son :m="money" @change="fn"></Son> -->
<!-- 父子传递数据,语法糖的写法 -->
<!-- <Son :m.sync="money"></Son> -->
<!-- v-model的原理是把money绑定在属性value中 绑定的事件名@input -->
<!-- <Son :value="money" @input="(data)=>money=data"></Son> -->
<!-- <Son v-model="money"></Son> -->
<Son :name="{a:1}" :age="2" @click="fn1"></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
data() {
return {
// money: "ABC" //传递的数据是大写
money: 400 //传递的数据是大写
};
},
components: {
Son
},
methods: {
fn1() {
alert(1);
},
fn(data) {
// 当父组件监听到子组件的点击事件执行了,绑定方法就执行,并且会拿到子组件对应传过来的值
this.money = data;
}
}
};
</script>
子组件:
<template>
<div>
Son
<!--
获取传过来的值用这个
-->
<!-- {{m}} -->
{{arr}}
{{obj}}
<!--这是v-model对应的值value -->
{{value}}
<!-- 这是修改过的值 -->
<!-- {{changeM}} -->
<!-- 直接使用这个$attrs可以获取父组件传过来的属性{ "name": {"a":1}, "age": 2 } -->
{{$attrs}}
{{$attrs.name}}
<!-- { "a": 1 }-->
<!-- 执行父组件的事件使用$listeners,里面的事件click() -->
<!-- {{$listeners.click()}} -->
<button @click="giveData">给父组件数据</button>
<!-- 把从父组件拿到的属性$attrs.name传给GrandSon组件 -->
<GrandSon v-bind="$attrs" :name1="$attrs.name" v-on="$listeners"></GrandSon>
</div>
</template>
<script>
import GrandSon from "./GrandSon";
export default {
// props: ["m"], //获取从父组件拿到的值使用,props
// computed: {
// //若想对传过来的值修改,例如变成小写的,推荐使用计算属性
// changeM() {
// return this.m.trim().toLowerCase();
// }
// },
props: {
// 验证传过来的值
m: {
type: [String, Number] //值的类型
// default: 100 //默认值 , 它与required不能同时使用,用一个就可以
// required: true //必传
// validator: value => {
// //自定义验证规则
// return value > 400 && value < 1000;
// }
},
arr: {
type: Array, //若是数组或对象,默认值是函数
default: () => [1]
},
obj: {
type: Object,
default: () => ({}) //ES6中,函数中的直接写{}是作用域,所以需要加()
},
value: {
//这是v-model对应的value
type: Number
}
},
methods: {
giveData() {
// 子组件执行父组件监听的事件,子组件使用$emit将数据发送给父组件
// this.$emit("change", 999); //change是监听的事件,999是参数
// this.$emit("update:m", 999); //若在父组件使用:m.sync='money',在这要使用update带属性名表示事件
this.$emit("input", 999); //使用v=model传的值,事件时input
}
},
components: {
GrandSon
}
};
</script>
GrandSon组件:
<template>
<div>
GrandSon
<!-- 这是从Son传来的来自Parent的数据,还有Parent的click事件,可以直接调用Parent组件中的事件 -->
{{$attrs}}{{name1}}
{{$listeners.click()}}
</div>
</template>
<script>
export default {
props: ["name1"]
};
</script>
<template>
<div>
Parent
<Son :name="{a:1}" :age="2" @click="fn1"></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
provide() {
return {
parentMsg: "Parent中使用provide定义的全局数据"
};
},
data() {
return {
money: 400 //传递的数据是大写
};
},
components: {
Son
},
methods: {
fn1() {
alert(1);
},
fn(data) {
// 当父组件监听到子组件的点击事件执行了,绑定方法就执行,并且会拿到子组件对应传过来的值
this.money = data;
}
}
};
</script>
GrandSon组件,使用inject注入Parent中定义的全局属性parentMsg:
<template>
<div>
GrandSon
<!-- 这是调用从全局注入的parentMsg -->
{{parentMsg}}
</div>
</template>
<script>
export default {
// 注入全局定义的parentMsg属性(定义的位置在Parent组件)
inject: ["parentMsg"],
props: ["name1"]
};
</script>
<template>
<div>
Parent
<Son :name="{a:1}" :age="2" @click="fn1"></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
data() {
return {
money: 400 //传递的数据是大写
};
},
components: {
Son
},
methods: {
fn1() {
alert("Parent组件中的方法111");
}
}
};
</script>
Son子组件:
<template>
<div>
Son
<GrandSon ref="grandSon"></GrandSon>
</div>
</template>
<script>
import GrandSon from "./GrandSon";
export default {
props: {
//这是v-model对应的value
value: {
type: Number
},
// 验证传过来的值
m: {
type: [String, Number] //值的类型
// default: 100 //默认值 , 它与required不能同时使用,用一个就可以
// required: true //必传
// validator: value => {
// //自定义验证规则
// return value > 400 && value < 1000;
// }
}
}
components: {
GrandSon
},
//DOM加载完成
mounted() {
// 调用父组件的方法:获取父组件,调用fn1的方法
// this.$parent.fn1();
// 调用子组件的方法:子组件是个数组,取第一个子组件的fn2方法
// this.$children[0].fn2();
// 调用子组件的方法:通过$refs.grandSon可以拿到GrandSon组件,同样可以调用fn2方法
this.$refs.grandSon.fn2();
}
};
</script>
GrandSon组件:
<template>
<div>
GrandSon
</div>
</template>
<script>
export default {
methods: {
fn2() {
alert("GrandSon222中的方法");
}
}
};
</script>
<template>
<div>
<!--3.使用组件 -->
<Parent></Parent>
</div>
</template>
<style scoped>
</style>
<script>
// 1.引入组件
import Parent from "./components/Parent";
import Vue from "vue";
export default {
data() {
return {};
},
components: {
Parent //2.注册组件
}
};
Vue.prototype.$bus = new Vue(); //$bus是公共的
</script>
父组件:
<template>
<div>
Parent
<Son :name="{a:1}" :age="2" @click="fn1"></Son>
<Brother></Brother>
</div>
</template>
<script>
import Son from "./Son";
import Brother from "./brother";
export default {
data() {
return {
// money: "ABC" //传递的数据是大写
money: 400 //传递的数据是大写
};
},
components: {
Son,
Brother
}
};
</script>
Son组件:
<template>
<div>
Son
<button @click="change">改变兄弟</button>
</div>
</template>
<script>
import GrandSon from "./GrandSon";
export default {
methods: {
change() {
this.$bus.$emit("test", 1000);
console.log(this.$bus);
}
}
};
</script>
Brother兄弟组件:
<template>
<div>我是Son组件的兄弟组件{{m}}</div>
</template>
<script>
export default {
mounted() {
this.$bus.$on("test", data => { //使用箭头函数,this指向现在的Vue示例,因要改当前Brother组件的m的值。若不用箭头函数,this指向App.vue中定义的存储值的vue实例
// console.log(data, this);
this.m = data;
});
},
data() {
return {
m: 222
};
}
};
</script>
执行:
vue serve App.vue
点击修改兄弟按钮,就可以看到运行结果了。
这里没有package.json文件,因是用的快速原型开发,下载完后(全局安装)就可以通过vue serve App.vue(入口文件名)使用。
学习代码已上传git