基础概念
1. 什么是Vue的组件?
组件是可复用的 Vue 实例, 把一些公共的模块抽取出来,然后写成单独的的工具组件或者页面,在需要的页面中就直接引入即可那么我们可以将其抽出为一个组件进行复用。例如 页面头部、侧边、内容区,尾部,上传图片,等多个页面要用到一样的就可以做成组件,提高了代码的复用率。
2.什么是子组件,什么是父组件?
子组件在父组件的 template 属性或者是模板中。
Vue传值的方式
1. 子向父传值,通过通过props关键字接收
父组件:
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<Header :addTodo="addTodo"></Header>
<List :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></List>
<Footer :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"></Footer>
</div>
</div>
</div>
</template>
<script>
import Header from "@/components/Header";
import List from "@/components/List";
import Footer from "@/components/footer";
export default {
name: 'App',
data() {
return {
todos:JSON.parse(localStorage.getItem('todos')) || []
// todos: [
// {id: '001', title: '测试数据1', done: false},
// {id: '002', title: '测试数据2', done: true},
// {id: '003', title: '测试数据3', done: false}
// ]
}
}, methods: {
addTodo(todoObj) {
this.todos.unshift(todoObj);
},
/* 勾选或者 取消勾选 */
checkTodo(id) {
this.todos.forEach((todo) => {
if (todo.id == id) {
todo.done = !todo.done;
return;
}
});
},
deleteTodo(id) {
this.todos = this.todos.filter(todo=>todo.id != id);
},
/* 全选 与 全反选 */
checkAllTodo(done){
this.todos.forEach(todo=> todo.done = done);
},clearAllTodo(){
this.todos = this.todos.filter(todo=> !todo.doen);
}
},
watch:{
todos:{
deep:true,
handler(value){
localStorage.setItem('todos',JSON.stringify(value))
}
}
},
components: {
Footer,
List,
Header
}
}
</script>
子组件之一
<template>
<ul class="todo-main">
<Item
v-for="todo in todos"
:key="todo.id"
:todo="todo"
:checkTodo="checkTodo"
:deleteTodo="deleteTodo"
>
</Item>
</ul>
</template>
<script>
import Item from "@/components/Item";
export default {
name: "List",
components: {Item},
props: ['todos', 'checkTodo', 'deleteTodo']
}
</script>
<style scoped>
.todo-main{
margin-left: 0px;
border: 1px solid #ccc;
border-radius: 2px;
padding: 0px;
}
</style>
通过props子组件可以接到值,而且子组件可以再向里套用子组件。
2. $emit 子组件向父组件传值
什么是全局事件总线?
一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
如图,这就是全局事件总线的执行流程,值是单项传递的。这种传值方式组件之间可以没有任何关系。
学校组件:
<template>
<div>
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>
</template>
<script>
export default {
name: "School",
data() {
return {
name: '猿究院',
address: '太白南路'
}
}, methods: {
myShowInfo(data) {
console.log("这是School组件,收到了数据:"+data);
}
},
mounted() {
this.$bus.$on('showInfo',this.myShowInfo)
},beforeDestroy() {
this.$bus.$off('showInfo');
}
}
</script>
<style scoped>
</style>
学生组件
<template>
<div>
<h2>学生姓名:{{ name }} </h2>
<h2>学生性别:{{ sex }} </h2>
<button @click="sendStudentName">点我传递学生信息</button>
</div>
</template>
<script>
export default {
name: "Student",
data() {
return {
name: '张三',
sex: '男'
}
},methods:{
sendStudentName(){
// $emit 触发事件 >>> $emit(eventName)
this.$bus.$emit('showInfo',this.name);
}
}
}
</script>
<style scoped>
</style>
App组件:
<template>
<div>
<School></School>
<Student ></Student>
</div>
</template>
<script>
import Student from "@/components/Student";
import School from "@/components/School";
export default {
name: 'App',
data() {
return {}
}, components: {
School,
Student
}
}
</script>
这种方式虽然简单好用。但是订阅和发布必须成对出现,不然就没有意义,由于在页面使用里的灵活性,一旦事件多了后,难以对事件进行维护。另外在订阅事件的组件里,必须手动销毁监听,否则会引发多次执行,对于一些包含业务逻辑的通信,复用性差,需要在多个地方重复写逻辑。
3. 通过ref属性获取值
调用方式:
this.$refs.ref名称.属性 和 this.$refs.ref名称.方法()
父组件:
<child :name="name" ref="child" />
mounted() {
console.log(this.$refs.child.year);
this.$refs.child.showName()
}
子组件:
export default {
data(){
return {
year:2022
}
},
methods:{
showName(){
console.log('toby:'+ this.year);
}
}
};
总结
Vue的传值方式有很多种,单个组件内可用插值表达式去实现,如果需要储存一些数据,也可以用localstorage方法去储存这些多次使用的数据。不过组件之间的传值方式需要注意使用的场景。