写在前面:
我是「沸羊羊_」,昵称来自于姓名的缩写 fyy ,之前呕心沥血经营的博客因手残意外注销,现经营此账号。
本人是个小菜,正向着全栈工程师的方向努力着,文章可能并不高产,也很基础,但每写一篇都在用心总结,请大佬勿喷。
如果您对编程有兴趣,请关注我的动态,一起学习研究。
感谢每位读者!
正文
vue组件化
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 js 特性进行了扩展的原生 HTML 元素。
父子组件传值
在 Vue 中,父子组件的关系可以总结为:prop 向下传递, 事件($emit) 向上传递。父组件通过 prop 给子组件下发数据,子组件通过 事件 给父组件发送消息。
注意:
父组件可以向子组件传递数据,传递过来的数据可以随意修改,但子组件不能随意修改父组件传递过来的数据,比如说:父组件向好几个子组件传递相同的数据,其中一个子组件修改值,因为接受到的是引用类型的数据,所以一个组件修改值,可能导致其他子组件引用修改的数据。这也是 Vue 官网提到的 单向数据流的概念。Vue 官网描述
父组件向子组件传值
父组件中需要进行的操作:
- import 子组件
- 注册 import 的子组件
- 使用子组件的地方,v-bind (绑定)要传递的属性值
//parent.vue
<template>
<div id="app">
<h3>我是父组件</h3>
<!-- 子组件, 绑定父组件要传递给子组件的值 -->
<childCom :child="msg"></childCom>
</div>
</template>
<script>
import childCom from "./child"; //引入子组件
export default {
components: { //注册子组件
childCom
},
data() {
return {
msg: "哈哈哈"
};
}
};
</script>
子组件中接收父组件的值:
- 使用 props 接收传递的值,props 是一个数组,比如:props:[“child”] , 数组里面的元素都是父组件传递过来的属性名,接收后可以当 data 中定义的属性一样使用,比如:{{child}}
- props 还可以使用对象方式接收,并设置类型,比如:props:{“child” : {type : String}},其中 type 是该属性值的类型,强调传递的值是 String 类型,它会进行验证,如果不是 String 类型,会报错。还可以设置 属性值的默认值,写法:props : {“child” : {type : String, default = “嘿嘿”}}
// child.vue
<template>
<div>
<h3>我是子组件</h3>
<div>{{child}}</div>
</div>
</template>
<script>
export default {
//接收从父组件传递的值
props: ["child"]
};
</script>
结果展示:
子组件向父组件传值
父组件中需要进行的操作:
- 在父组件中 import 子组件,注册子组件,使用子组件并v-bind 属性值
- 使用子组件时 v-on 绑定方法名
- 父组件中定义绑定的方法,此方法名要与 v-on 绑定的方法名一致
// parent.vue
<template>
<div id="app">
<h3>我是父组件</h3>
<!-- 使用子组件,绑定属性值与方法 -->
<childCom :child="msg" @passMethods="passMethod"></childCom>
</div>
</template>
<script>
import childCom from "./child"; //引入子组件
export default {
//注册子组件
components: {
childCom
},
data() {
return {
msg: "哈哈哈"
};
},
methods: {
//子组件中绑定的方法
passMethod(data) {
this.msg = data;
}
}
};
</script>
子组件向父组件传递值:
- 用 emit 向父组件传递值,比如:this.$emit(“passMethods”, “修改父组件的msg”); 第一个参数是父组件中绑定的事件(@passMethods),这两个名字一定要相同,第二个参数是传递的值
- 子组件标签中绑定 emit 的方法
// child.vue
<template>
<div>
<h3>我是子组件</h3>
<!-- 插值表达式,显示传递的值 -->
<div>{{child}}</div>
<br />
<!-- 按钮,点击事件绑定方法 -->
<el-button @click="passMethods">点击,子组件传递值给父组件</el-button>
</div>
</template>
<script>
export default {
//接收从父组件传递的值
props: ["child"],
methods: {
// 点击事件绑定方法
passMethods() {
this.$emit("passMethods", "修改父组件的msg");
}
}
};
</script>
结果展示:
兄弟组件间传值
兄弟组件的概念是什么?图中组件分为了三层,上面讲解的是 1 与 2 进行传值,那兄弟组件就是 3 和 3 之间传值。那我们是不是需要 3-2-1-2-3,这种方式进行传递呢?答案是可以实现,但也太麻烦了吧!
打个比方:老师当作父组件,学生当作子组件,考试的时候,学生的笔坏了,想向旁边的同学借笔,这时候,学生举手说:老师,我想借根笔。老师会拿旁边同学的笔给他。如果兄弟组件可以传值,就不用老师进行传递了,两个同学可以独立完成借笔这个操作。这也就是:观察者模式(也叫发布订阅模式/总线模式/Bus)
<body>
<div id="root">
<!-- 声明两个子组件 -->
<child content='点赞收藏关注一条龙'></child>
<child content='不可能只点赞收藏'></child>
<script src="./vue.js"></script>
</div>
<script type="text/javascript">
// 给每个vue实例添加 bus 属性,起到总线的作用
Vue.prototype.bus = new Vue()
// 声明全局子组件,名为 child
Vue.component('child',{
data:function(){
return {
childContent:this.content
}
},
props:{
content:String
},
// click事件绑定handleclick方法
template:'<div @click="handleclick">{{childContent}}</div>',
methods:{
handleclick:function(){
// 子组件向外触发 change 事件,携带content值
this.bus.$emit('change',this.content)
}
},
mounted:function(){
var vm=this;
// 组件挂载时,触发声明周期钩子mounted,用于监听 change 事件,接收传递的值
this.bus.$on('change',function(msg){
vm.childContent=msg;
})
}
})
//新建vue实例进行挂载
var vm=new Vue({
el:'#root'
})
</script>
</body>
结果展示:
我们来捋一遍整个过程如何实现的?:
我们点击文字,触发组件内的 handleclick 事件,handleclick 事件向总线触发 ‘change’ 事件,并将值传递过去。两个子组件被挂载完成时,都会执行 mounted 函数钩子,将各自组件保存在变量 vm 中,然后监听的 ‘change’ 事件被触发,将事件携带的值,传递给各自子组件的值。点击的文字的值传递过去,值不变;未点击的文字的值传递过去,改变了。这样,就实现了组件间传值。
不相关组件间传值
使用 vuex 进行传值,在 vue 项目中安装插件 vuex 插件。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
至于如何使用 vuex 进行传值呢?
A页面向B页面传值。
- A页面将值存储到 store.js 中
- B从 store.js 中进行读取
//A页面将数据存储到 store.js 中
this.$store.commit("setAData", this.data); // 存储当前数据
//store.js 文件中进行接收
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
//接收A页面传递的数据
setAData(state, data) {
state.data = data;
},
}
})
//B页面读取 store.js 中的数据
//写法一
computed:{
getAData(){
return this.$store.state.data
}
},
//写法二
import { mapState } from "vuex"; // 引入vuex用于将全局变量映射为页面变量
computed:{
...mapState([ //解构到计算属性中
'data' //store.js 中的数据
])
},
//写法三
import { mapState } from "vuex"; // 引入vuex用于将全局变量映射为页面变量
computed:{
...mapState([ //解构到计算属性中
Bdata:'data' //重命名
])
},
注意:
- 官方建议我们将 this.$store.state.xxx 放到计算属性中使用,可以让代码看起来更优雅。
- 每次读取 store.js 中的数据时,不需要用 this.$store.state.xxx 这种方式进行读取,使用写法二 …mapState 解构到当前页面的方式让代码更优雅
最后
以上为本人的一点学习记录与总结,如有错误,请指出,不胜感激。