一、组件化开发
组件是Vue.js中重要思想
- 它提供了一种抽象, 我们可以开发出一个独立可复用的小组件来构造我们的应用组件
- 可以扩展 HTML 元素,封装可重用的代码
- 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
组件化思想应用
- 有了组件化的思想, 我们之后开发中就要充分的利用它
- 尽可能将页面拆分成一个个小的, 可复用的组件
- 这样让我们代码更方便组织和管理, 并且扩展性也强
二、组件分类
1、全局组件–component
配置一次之后 再所有地方都可以直接使用
我们把引用和调用写在main.js中
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 配置全局组件
import BottomBar from "./components/BottomBar.vue"
Vue.component("BottomBar",BottomBar)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
但是请勿滥用全局组件 因为全局组件会造成组件名污染
2、局部组件–components
局部组件构建依赖于一个固定的 vue 实例配置,通过配置实例属性
components:{} 定义
局部组件仅限构建 vue 实例的容器范围中使用
语法构成 : components:{ name:definition,…… }
参数 :
name (string) : 定义组件唯一名称,在页面中作为组件调用的标签名;
definition (Object) :描述组件的相关配置特性(等效 Vue.createApp 的
options 参数)
三、组件间的通信
1、父子组件间的通信
1.1 父组件传值给子组件 正向传值
要通过 props 属性将number进行传递给子组件才可以。
子组件设置接收 props
export default {
// 1.使用props定义接收参数
props:["xiaoming","xiaohong"]
}
父组件传递
<ZiCom xiaoming="我是传递的数据a" xiaohong='我是传递的第二个b'/>
props验证
在接收父组件传递过来数据的时候 进行一个验证 验证数据类型 默认值 或者非空等校验 约束数据传递过来的值
语法:
props:{
接收参数:{
type:你的数据类型 Number String Boolean Object Array
}
}
设置默认值:
props:{
接收参数:{
type:你的数据类型 Number String Boolean Object Array,
defalut:你设置的默认值
}
}
非空设置:不能和默认是同时使用 required
props:{
num:{
type:Number,
// default:9527
required:true
}
}
子组件中,data中的数据和props中的数据的区别?
- 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上。props 中的数据,都是通过 父组件 传递给子组件的。
- data中的数据是可读可写的;props中的属性只是可读的,无法重新赋值,重新赋值会报错(也就是说,子组件不要直接去修改父组件中的数据)。
1.2 子组件传值给父组件 逆向传值
子组件通过事件触发的形式,向父组件传值
- 自定义事件 携带我们子组件的数据
this.$emit(“给自定义事件起个名字”,你传递的数据)
- 绑定自定义事件
<ZiCom @自定义事件=“函数”/> 当$emit被触发的时候,自定义事件被触发,对应的处理函数被触发。左边this.count是实参,传递给右边val形参。
- 定义函数 并且接收自定义事件上面的数据
2、同胞/兄弟传值-中央事件总线eventBus
什么是同胞/兄弟传值?
多个组件有一个相同的父组件,两个兄弟之间的数据传递
什么是中央事件总线?
就是凌驾在多个兄弟组件之上的一个空vue实例 这个空vue实例就是中央事件总线, event-bus实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件(其实,也可以实现父子)通信的一种解决方案。
实现
1.创建这个中央事件总线 再src下创建一个文件夹 里面创建一个xx.js
2.在数据发送方,调用 bus.$ emit(‘事件名称’, 要发送的数据) 方法触发自定义事件;
3.在数据接收方,调用 bus.$on(‘事件名称’, 事件处理函数) 方法注册一个自定义事件。
扩展:正逆向传值
$ parent 访问父组件实例
1.如果组件没有父组件,他的$ parent为undefined
2.App组件(根组件)的$ parent不是undefined,也不是App本身 而是vue实例对象。
3.如果组件有多个父组件 那么每次被调用的时候 p a r e n t 会指向不同的父组件 ∗ ∗ ( 这条就决定了 parent会指向不同的父组件**(这条就决定了 parent会指向不同的父组件∗∗(这条就决定了parent不会在工作用使用太多 因为不好确定他的父组件是那个) 子实例可以用 this.$parent
访问父实例 即可使用父组件的属性和方法
mounted(){
console.log("父组件",this.$parent)
}
$children 访问子组件的实例
可以获取到当前组件的直接子组件(只是他的儿子组件。其他的孙子等组件不算),并以数组的形式返回(因为一个父组件可能有很多个子组件)
mounted(){
console.log(this.$children);
}
需要注意
$children
并不保证顺序,也不是响应式的。
$attrs
就是一个容器对象,这个容器对象会存: 父组件传过来的且子组件未使用props声明接收的数据,如果父组件传递的数据仅仅只想完成一些逻辑操作 不在页面展示 那么我们就不需要使用props 直接使用attrs接受更加方便
依赖注入
祖先组件可向其所有子孙后代传递数据。**provide 和 inject 需要成对使用。
provide/inject 可以轻松实现跨级访问数据**,不推荐使用,因为数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个层级使用了。如果数据在多个组件都需要使用到,可以使用 vueX 来进行状态管理。如果只是子组件想要使用父组件上的数据,可直接通过 props 来让父组件给子组件传值。
3、跨组件传值
VUEX
概念
vuex就是在vue中的统一状态(数据)管理工具 把项目下的所有数据 统一的放到这个仓库里面 组件谁想用 谁就去这个仓库里面取 没有了复杂的数据流动
vuex5大属性
1. state—数据源
state属性的作用 就是在vuex中存放数据的 我们今后在vuex的所有数据都写在state中
使用state的数据
因为vuex是统一状态管理 所以在项目下的任何数据 都可以直接使用state的数据
方式1 直接读取
> 语法: this.$store.state.xxx
方式2 使用计算属性间接读取(推荐使用)
<template>
<div class="about">
<h1>This is an about page---{
{
this.$store.state.text}}</h1>
<h1>计算属性方式-- {
{
newbool}}</h1>
</div>
</template>
<script> export default{
computed:{
newbool(){
return this.$store.state.bool
}
} }
</script>
方式3 vuex的辅助函数(简化了我们操纵vuex数据的复杂度)mapState—>数组用法
<template>
<div class="sunClass">
组件
<h1>aa{
{
texta}}</h1>
<h1>aa{
{
obj.name}}</h1>
</div>
</template>
<script>
import {
mapState} from "vuex"
export default {
// 使用mapState
computed:{
// 名字需要和vuex的state数据名相同
...mapState(["texta","obj"])
}
};
</script>
方式4 vuex的辅助函数mapState—>对象用法
<template>
<div class="sunClass">
组件
<h1>aa{
{
xiaoming}}</h1>
<h1>aa{
{
xiaohong.name}}</h1>
</div>
</template>
<script>
import {
mapState} from "vuex"
export default {
// 使用mapState
computed:{
// 对象用法
...mapState({
xiaoming:(state)=>state.texta,
xiaohong:(state)=>state.obj,
})
}
};
</script>
2、module—模块
随着项目的体积逐渐增大 那么变量与今后的其他操纵就会在vuex的文件中 增多 导致这个文件中的内容原来越冗余 后期也几乎无法维护,为了避免上述情况 所以我们可以使用vuex的模块把内容进行拆分
1.在store文件夹下创建文件夹用来存放我们拆分的模块
2.创建模块文件 写入如下内容
let aboutm={
state: {
//就是数据源 存放数据的地方
text:"我是字符串",
bool:true,
},
getters: {
},
mutations: {
},
actions: {
},
}
// 必须暴露
export default aboutm
3.关联并使用我们创建的模块
import Vue from 'vue'
import Vuex from 'vuex'
// 1.引用模块
import homem from "./modules/homem.js"
import aboutm from "./modules/aboutm.js"
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
//2配置模块
homem,
aboutm
}
})
3、mutations—修改数据
mutations的作用就是在vuex中修改state的 如果想修改state的数据必须使用mutations来修改
想要修改state的数据 那么就是用 commit 调用mutations修改 state
组件内使用commit调用
methods:{
add(){
// 调用vuex的修改
// this.$store.commit("你调用的mutations名字随便写",你想给mutations的数据 可选)
this.$store.commit("NUM_LIST_ADD_DATA")
},
del(){
this.$store.commit("NUM_LIST_DEL_DATA")
}
},
创建mutations中的内容
let homem={
state: {
//就是数据源 存放数据的地方
num:666
},
getters: {
},
mutations: {
// state是一个形参可以随便写但是建议写state
// 这个形参的作用就是代表上面的数据源
NUM_LIST_ADD_DATA(state){
state.num++
},
NUM_LIST_DEL_DATA(state){
state.num--
},
},
actions: {
},
}
// 必须暴露
export default homem
mutations的payload
在我们使用commit()的时候 第一个参数是你要调用的修改动作名 第二个参数是你要给mutations传递的数据
methods:{
add(){
// 调用vuex的修改
// this.$store.commit("你调用的mutations名字随便写",你想给mutations的数据 可选)
this.$store.commit("NUM_LIST_ADD_DATA",{
inputval:this.inputval})
},
del(){
this.$store.commit("NUM_LIST_DEL_DATA",{
inputval:this.inputval})
}
}
在mutations中可以读取这个第二个参数
mutations: {
// state是一个形参可以随便写但是建议写state
// 这个形参的作用就是代表上面的数据源
// 第二个参数就是payload (载荷) payload就是接受commit的第二个参数
NUM_LIST_ADD_DATA(state,payload){
state.num=state.num+payload.inputval
},
NUM_LIST_DEL_DATA(state,payload){
state.num=state.num-payload.inputval
},
},
Vuex辅助函数–mapMutations
<template>
<div class="sunClass">
组件
<h1>{
{
com.texta}}</h1>
<button @click="uptexta('传递的数据')">点我修改</button>
</div>
</template>
<script>
import {
mapState,mapMutations} from "vuex"
export default {
computed:{
...mapState(["com"])
},
methods:{
// 填入mutations的名字
...mapMutations(["uptexta"]),
}
};
</script>
4、actions—异步触发器
actions是vuex的一个属性 他的作用就是在vuex中进行异步操作的触发(很多同学后期总爱说actions是异步请求 但是要注意他不是异步请求 他是进行异步操纵的触发 异步请求只是它触发的众多异步操纵的其中一种)
语法:要触发actions使用dispatch (dispath触发actions进行异步触发 把请求来的数据
通过commit交给mutations修改state 在页面读取展示)
1.在组件内使用dispatch()触发vuex的actions进行异步请求的发送
2.需要在对应的actions创建你要触发的异步触发器
3.把请求来的数据通过context.commit()触发修改
4创建对应mutations修改state
Vuex辅助函数mapActions
<template>
<div class="sunClass">
组件
<h1>{
{
com.texta}}</h1>
<button @click="axioslink()">点我进行异步操作</button>
</div>
</template>
<script>
import {
mapState,mapActions} from "vuex"
export default {
computed:{
...mapState(["com"])
},
methods:{
...mapActions(["axioslink"])
}
};
</script>
5、getters—vuex的计算属性
vue的计算属性是computed 对data的数据进行依赖 处理之后返回新的计算之后的结果
vuex的getters也是计算属性 只是他和上面的computed最大的区别就是 他处理的数据可以在任何组件直接使用 而vue的computed 处理的数据只能在当前组件使用
getters: {
// state就是上面的数据源
newtext(state){
return state.text.toUpperCase()
}
}, 使用: this.$store.getters.xxx
Vuex辅助函数mapGetters
<template>
<div class="sunClass">
组件
<h1>getters的:{
{
upperTexta}}</h1>
</div>
</template>
<script>
import {
mapState,mapGetters} from "vuex"
export default {
computed:{
...mapState(["com"]),
...mapGetters(["upperTexta"])
},
};
</script>
vuex数据修改刷新丢失
刷新页面vuex的数据会丢失属于正常现象,因为JS的数据都是保存在浏览器的堆栈内存里面的,刷新浏览器页面,以前堆栈申请的内存被释放,这就是浏览器的运行机制,那么堆栈里的数据自然就清空了。
解决方法:vuex-along
1.安装 vuex-along:
npm install vuex-along --save
2.在store文件夹里的index.js中引入vuex-along并配置相关代码
本质:就是可以把数据在刷新的时候先存储到本地存储中 当刷新之后再重新取出来 赋值给vuex的state