vue基础
一、vue的基本认识
二、vue的指令
1.插值表达式
语法
<template>
<div>
<ul>
<li>{{value}}</li> 语法为{{变量}},变量要在data函数返回的对象里声明
</ul>
</div>
</template>
<script>
export default {
data () {
return {
value:'张三'
}
}
};
</script>
<style>
</style>
2.v-bind
v-bind可以将变量和标签的属性值绑定在一起
语法
<template>
<div>
<a v-bind:href="link">百度</a> v-bind:属性名="变量"
<a :href="link">百度</a> v-bind简写 => :属性名="变量"
</div>
</template>
<script>
export default {
data () {
return {
link:'https://www.baidu.com'
}
}
};
</script>
<style>
</style>
3.v-on
给元素绑定事件
语法
<template>
<div>
<a href="https://www.baidu.com" @click="fn1">跳转</a>
<a href="https://www.baidu.com" @click="fn2($event,10)">跳转</a>
</div>
</template>
<script>
export default {
// 方法写在methods对象里
methods: {
fn1(e) {
e.preventDefault(); // 当函数未携带参数时,默认的参数就是e
},
fn2(e,num) { // 当函数有多个参数时,e和$event位置要对应才能阻止默认行为
console.log(num);
e.preventDefault(); // 和$event位置对应即可
},
}
};
</script>
<style>
</style>
v-on的修饰符
语法 @事件名.修饰符="事件函数"
<a href="https://www.baidu.com" @click.once="fn1">跳转</a>
.once表示只能触发一次,.prevent表示阻止默认行为,.stop表示阻止冒泡
4.v-model
<template>
<div>
用户名<input type="text" v-model="username"><br>
密码<input type="text" v-model="password"><br>
<button @click="login">登录</button>
</div>
</template>
<script>
// v-model绑定后,一个变化,另一个也会发生变化,input的value和变量双向绑定
export default {
data() {
return {
username:'123',
password:''
}
},
methods: {
login() {
console.log(this.username,this.password);
}
}
};
</script>
<style>
</style>
v-model修饰符
.number 表示转换成数字类型
.trim 表示去除首尾空白符
.lazy 表示当表单失去焦点时才赋值
5.v-for
<template>
<div>
对象格式
<ul>
<!-- value相当于属性值"张三"等 -->
<li v-for="value in obj">{{ value }}</li>
</ul>
<!-- obj.key = value -->
<li v-for="(value, key) in obj">{{ key }}:{{ value }}</li>
</ul>
字符串格式
<ul>
<li v-for="value in str">{{ value }}</li>
</ul>
<ul>
<!-- 这里的index和数组下标一个道理,数字类型的index也等同 -->
<li v-for="(value, index) in str">{{ index }}:{{ value }}</li>
</ul>
数字格式
<ul>
<!-- 数字遍历表示从1到num -->
<li v-for="value in num">{{ value }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
obj:{
name:"张三",
age:198,
sex:"男"
},
str:"捏麻麻地太潮啦",
num:5
};
},
};
</script>
<style>
</style>
tips:当v-for不加上 :key 时,默认的是就地更新,会将新旧数据结构进行对比,在旧的dom基础上进行修改
缺点:
当用表单的输入值渲染页面时, input是临时DOM状态,在元素复用时,input里的值也是会被保留的。
通过加上:key="唯一标识",vue就会根据这个唯一标识的变化重新排列元素顺序,并且会移除 key 不存在的元素
6.v-text和v-html
<template>
<div>
<!-- v-text不会解析标签 -->
<p v-text="text"></p> 在页面上显示的是<button>点击<button>的文字
<!-- v-html可以解析标签 -->
<p v-html="html"></p> 在页面上显示的是按钮
</div>
</template>
<script>
export default {
data () {
return {
text:'文本内容',
html:'<button>点击</button>'
}
}
}
</script>
<style>
</style>
7.v-show和v-if
<template>
<div>
v-show原理是控制display:none来控制标签显示隐藏,条件为true则显示,false则隐藏
<h1 v-show="num > 4000">4000+</h1>
<h1 v-show="num <= 4000">4000-</h1>
v-if原理是删除标签来控制标签显示隐藏,条件为true则显示(新建dom元素),false则删除(删除dom元素)
<h1 v-if="num > 4000">4000+</h1>
<h1 v-if="num <= 4000">4000-</h1>
<!-- 大部分情况下,v-show和v-if可以相互替换 -->
</div>
</template>
<script>
export default {
data () {
return {
num:4001
}
}
}
</script>
<style>
</style>
tips:v-else和v-else-if的使用语法和if else else if 的语法相同 , 但是注意要在同级且相邻的标签中使用
8.:class和:style
<template>
利用v-bind动态修改类名 => :class="{类名:布尔值}" true为添加类名,false为移除类名
<div :class="{ daylight: flag }" @click="change"></div>
动态设置stlye样式 => :style="{css属性名:css属性值}" 其中,css属性名可以用小驼峰也可以用''包着
<div :style="{ 'background-color': 'red' }" @click="change"></div>
</template>
<script>
export default {
data() {
return {
flag: false,
};
},
};
</script>
<style>
.daylight {
background-color: #fff;
}
</style>
三、vue的属性
1.过滤器
作用就是将一些数据的格式处理成我们想要的格式
1.在vue单文件下声明
<template>
<div>
<h1>{{ 9 | addZero }}</h1> 数字补零
<h2>{{ 'hello' | toUp }}</h2> 转大写
<h3>{{ 'hello' | reverse}}</h3> 反转,在mian.js进行全局声明
</div>
</template>
<script>
export default {
//
filters: {
addZero(num) {
return `${num < 10 ? "0" + num : num}`;
},
toUp(str) {
return str.toUpperCase();
}
},
};
</script>
<style>
</style>
2.在main.js中进行声明,vue过滤器在main.js声明可以在别的页面使用
<script>
Vue.filter('reverse', str => str.split('').reverse().join(''))
</script>
2.计算属性
<template>
<div>
计算属性的语法为{{ 计算属性名 }},并且要在computed对象里进行方法声明
<h1>{{ sum }} = {{ a }} + {{ b }}</h1>
a<input type="number" v-model.number="a" />
<br />
b<input type="number" v-model.number="b" />
</div>
</template>
<script>
export default {
data() {
return {
a: 25,
b: 26,
};
},
computed: {
// 函数名为计算属性名,要有返回值
sum() {
return this.a + this.b;
},
},
};
</script>
<style>
</style>
优点:提高性能(笑)
3.监听器
<template>
<div>
<!-- 简单数据类型 -->
<input type="text" v-model="value">
<br>
<!-- 复杂数据类型 -->
<input type="text" v-model="user.name">
<br>
<!-- 立即执行 -->
<input type="text" v-model.number="num">
总价:{{sum}}
</div>
</template>
<script>
export default {
data () {
return {
value:'',
user:{
name:'zs'
},
num:2,
sum:0
}
},
// 监听器作为方法放在watch对象里
watch: {
// 方法名是要监听的变量
value(newValue,oldValue) {
console.log('新:',newValue,'旧:',oldValue);
},
// 监听复杂数据类型写法
user:{
deep:true, // deep为true表示深监听
handler(newVal,oldVal) { // 监听复杂数据类型的新旧值都会返回最新的值
// tips:浏览器打印数据类型,只有当你鼠标点击展开对象时才会去赋值
console.log(newVal,oldVal);
}
},
num: {
immediate:true, // 这里表示在打开页面的时候就立即执行一次
handler(newVal) {
this.sum += newVal
}
}
}
}
</script>
<style>
</style>
四、vue的组件
1.组件的概念
组件是可复用的new实例,一个vue文件就是一个组件。当我们所写代码重复性高,过于冗余时,可以使用组件将代码拆分,从而达到结构简洁的效果
2.组件的全局引入和局部引入
全局引入
在main.js里引入
import 组件对象 form '文件路径'
Vue.component('组件名',组件对象)
引入后所有vue文件都可以使用这个组件,作为自定义标签使用
<组件名 />
局部引入
在需要引入的文件里使用
<script>
import 组件对象 form '文件路径'
export default {
components: { 组件对象 },
};
</script>
3.父组件向子组件传值
在父组件中
<template>
<!-- 第一步,定义所要传递给子组件的变量,若想传递变量,则利用:自定义属性接收;若传递的是字符串,可直接在子组件标签中设置自定义属性进行接收 -->
<div>
<changeColor :personName="value" />
</div>
</template>
在子组件中
<template>
<div>
<!-- 第三步,在子组件中直接使用 -->
<div>{{personName}}</div>
</div>
</template>
<script>
export default {
// 第二步,将父组件的自定义属性名放到props数组中,注意加引号
props: ['personName']
}
</script>
4.子组件向父组件传值
在子组件中
<script>
// 第一步,利用this.$emit()进行数据传递,第一个参数是自定义函数名,后续的参数都是你想传递的什么参数
this.$emit('delPrice',this.index,10)
</script>
在父组件中
<template>
<div>
<!-- 第二步,定义父组件接收数据的函数,语法 @子组件所传递的自定义函数名="处理业务代码的函数" -->
<changeColor @delPrice="delPrice"/>
</div>
</template>
<script>
methods: {
// 第三步,写业务代码
delPrice(index, price) {
// 业务代码
},
},
</script>
五、vue的生命周期
1.什么是vue的生命周期
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
2.vue的四个周期
vue分为四个周期,初始化、挂载、更新、销毁
每个周期又分别有两个钩子函数
①初始化
beforeCreate() 实例创建前触发
created() 实例创建完成,但此时dom元素还未开始渲染,可以在这里发送ajax请求拿数据
②挂载
beforeMount() 会在此时去找到虚拟Dom,并将其编译成Render
mounted() 虚拟Dom已经被挂载到真实Dom上,此时我们可以获取Dom节点,$refs 在此时也是可以访问的。
③更新
beforeUpdate() 响应式数据更新的时候会被调用,beforeUpdate的阶段虚拟Dom还没更新,所以在此时依旧可以访问现有的Dom。
updated() 此时补丁已经打完了,Dom已经更新完毕,可以执行一些依赖新Dom的操作。
④销毁
beforeDestroy() 在Vue实例销毁之前被调用,在此时我们的实例还未被销毁,在这个阶段可以做销毁定时器等操作
destroyed() vue实例被销毁,绑在实例身上的属性事件等都会被销毁
六、 refs
1.$refs
<template>
<div>
<refBox ref="refMe" id="box" />
</div>
</template>
<script>
import refBox from "@/components/02 $refs的用法子组件.vue";
export default {
components: {
refBox
},
mounted () {
console.log(document.querySelector('#box'));
console.log(this.$refs.refMe);
setTimeout(() => {
// 类似自定义属性,给标签设置ref属性,用this.$refs.设置的属性名来获取。如果是子组件标签,this.$refs可以获取子组件的所有数据和方法
this.$refs.refMe.msg = '父组件'
this.$refs.refMe.sayHi()
},1000)
}
}
</script>
<style>
</style>
2.$nextTick
<template>
<div>
<button @click="del">开始搜索</button>
<input v-if="flag" ref="ipt" type="text">
</div>
</template>
<script>
export default {
data () {
return {
flag:false
}
},
methods: {
del() {
this.flag = !this.flag;
// this.$nextTick(回调函数) 当页面渲染完毕后,才会触发回调函数。主要用于数据更新时想立即获取最新的值
this.$nextTick(() => {
this.$refs.ipt.focus();
})
}
}
}
</script>
<style>
</style>
七、动态切换组件
父组件内
<template>
<div>
<button @click="check = 'sonOne' ">子一</button>
<button @click="check = 'sonTwo' ">子二</button>
keep-alive包起来的子组件标签会被缓存到内存中,这样就可以避免重复创建而浪费性能,数据也会得到保存
<keep-alive>
<!-- 将components作为自定义标签,给components通过v-bind添加is属性,与接收组件名的变量关联起来 -->
<Components :is="check" /> is绑定的是那个组件名就显示哪个组件
</keep-alive>
</div>
</template>
<script>
import sonOne from "@/components/04 动态切换组件-子组件1.vue";
import sonTwo from "@/components/04 动态切换组件-子组件2.vue";
export default {
data () {
return {
// 这里的组件名是字符串格式
check:'sonOne'
}
},
components: {
sonOne,
sonTwo
}
}
</script>
<style>
</style>
子组件内
<template>
<div>天才</div>
</template>
<script>
export default {
created () {
// 当父组件Components未用keep-alive标签包裹时,这里的log会在标签出现时被打印,说明Components动态切换组件是创建和销毁的过程(不加keep-alive)
console.log('被创建啦');
}
}
</script>
<style scoped>
div {
height: 200px;
display: flex;
background-color: aqua;
justify-content: center;
align-items: center;
}
</style>
tips:动态切换组件用keep-alive标签包裹的话会触发自身独有且仅有的两个钩子函数(因为被keep-alive标签包裹的组件在第一次创建后会被缓存,所以就没有被创建和被销毁这个概念),activated()和deactivated()。
activated()是在组件被激活时侯触发,deactivated()是在组件失去激活状态时侯触发
八、slot插槽
1.slot匿名插槽
父组件内
<template>
<div>
<!-- 使用slot时,自定义标签要设置为双标签,双标签包裹的标签结构就是要传进去的标签结构 -->
<sonC>
<p>月初1</p>
</sonC>
<sonC>
<button>哈哈</button>
</sonC>
<!-- 这里什么都没传给子组件,显示的就是子组件准备的默认内容 -->
<sonC />
</div>
</template>
<script>
import sonC from "@/components/05 slot组件插槽的使用-子组件.vue";
export default {
components: {
sonC
}
}
</script>
子组件内
<template>
<div>
<div class="box">
<!-- 用slot接收时,可以用单标签,也可以双。接收的就是父组件传过来的标签结构 -->
<slot />
当要设置默认值时,slot要写成双标签,里面包裹着默认内容。当父组件未传标签过来时,默认显示的是包裹的内容
<slot>
<p>这是默认内容</p>
</slot>
</div>
</div>
</template>
<script>
export default {
}
</script>
2.slot具名插槽
父组件内
<template>
<div>
<sonC>
<!-- 如果想要在子组件中多处使用slot插槽,父组件需要在子组件自定义标签内用template双标签将自定义的标签包裹起来,通过v-slot属性和在子组件的slot上的name属性对应,就会在name对应的地方插入标签 -->
<template #left="obj">
<!-- 在v-slot属性上可以绑定一个变量名,这个变量是一个对象,这个对象包含子组件传过来的所有数据 -->
<p>{{obj.data.first}}</p>
</template>
<template #right="obj">
<button>{{obj.data.second}}</button>
</template>
</sonC>
</div>
</template>
<script>
import sonC from "@/components/06 slot具名插槽-子组件.vue";
export default {
components: {
sonC,
},
};
</script>
子组件内
<template>
<div>
<div class="box">
<!-- 这里用name对应父组件插入的位置,通过v-bind给父组件传值,父组件通过v-slot来接收 -->
<slot name="left" :data="list" />
<hr>
<slot name="right" :data="list" />
</div>
</div>
</template>
<script>
export default {
data () {
return {
list:{
first:'一月',
second:'二月'
}
}
}
}
</script>
tips:#是v-slot:的简写
九、自定义指令
局部注册方式
<template>
<div>
<!-- 自定义指令使用方式和vue自带的一致 -->
<div v-bgc=" 'red' " class="box"></div>
</div>
</template>
<script>
export default {
// 局部注册方式
directives: {
// 指令名 :{ 方法 }
bgc:{
// 在dom元素被插入后触发的函数
inserted(el,options) { // 这里的第一个形参就是使用指令的那个dom元素,后面的形参都是自定义指令传过来的变量
el.style.backgroundColor = options.value //传过来的变量放在形参的value里
},
// 当dom元素的值或模板更新时会触发这个函数
update(参数与上述一致) {
// 业务代码
}
}
}
}
</script>
全局注册方式(在mian.js里注册,注册后用法与局部注册一致)
<script>
Vue.directive("指令名",{
"inserted" (dom) {
// 对dom标签额外做什么功能
}
})
</script>
tips:自定义指令是vue指令的拓展,当vue指令不能满足我们的一些需求时,就可使用自定义指令
tips:自定义指令所绑定的dom元素有两个钩子函数,一个是inserted(),在dom元素被插入后触发;一个是update(),当dom元素的值或模板更新时触发
tips:使用钩子函数时可以接收自定义指令所传过来的值,inserted(el,options),el就是所绑的dom元素,options就是自定义指令所绑的变量值,注意这个变量值是放在options.value里
十、路由
1.路由的概念
路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转
因为vue都是单页面应用,所有内容都在一个页面上显示,很少使用html跳转去新页面显示。而靠路由实现的页面跳转则没有真正的html跳转
路由又隐性的把组件进行了两种分类(本质并无区别),分为页面组件和复用组件。页面组件是负责路由跳转的组件,复用组件则是每个页面使用的多处都用到的组件
2.引入路由和路由的配置
在mian.js里进行引入
<script>
// 1. 引入库
import VueRouter from 'vue-router'
// 2.在 Vue 安装这个库
Vue.use(VueRouter)
// 3 引入组件对象
import Find from '@/views/Find.vue'
import My from '@/views/My.vue'
// 4 配置路由表(决定在哪个路径显示哪个组件)
const routes = [
{
// path 路径
path: '/find',
// component 组件
component: Find
},
{
path: '/my',
component: My,
// 这个属性表示重定向,就是当页面跳转到当前组件时,强制跳转到目标路径
redirect: '/find/ranking',
},
{
// 表示匹配上述配置表之外的所有路径,常用于做404页面
path: '*',
component: Found404
}
]
// 3. 创建一个实例
const router = new VueRouter({
// 配置对象
routes //因为这里的变量名固定写法为routes,在上面声明的配置名最好与这个相同,方便简写
})
new Vue({
// 4. 挂载到 new Vue 根实例上
router, // 和上面简写道理一样
render: h => h(App),
}).$mount('#app')
</script>
在需要使用的页面组件上进行挂载
<template>
<div>
<!-- 路由挂载的地方 -->
<router-view></router-view>
</div>
</template>
tips:在mian.js引入路由中,用上了两次简写,一个是routes:routes,另一个是router:router
3.声明式导航和编程式导航
在Vue中路由跳转可以有两种方式: 声明式和编程式
声明式
<template>
<div>
<router-link to="/home/news">News</router-link>
<router-link to="/home/mes">Mes</router-link>
<router-view></router-view>
</div>
</template>
像上述一样,直接在组件里写router-link标签,用to属性进行页面组件的跳转,但整个页面没有进行跳转。这种就叫做声明式导航
编程式
<template>
<div>
<button @click="change">跳转</button>
</div>
</template>
<script>
export default {
methods: {
change() {
// 利用button点击进行页面的跳转
this.$router.push('/part')
}
}
}
</script>
利用this.$router.push()方法进行页面组件的切换,同时页面也会发生跳转,这样叫做编程式导航
编程式导航的传参
在传递参数的组件内
<!-- query传递参数写法:在路径后面拼接 ?+键值对 -->
<router-link to="/my/?name=张三">我的音乐</router-link>
<!-- params传递参数写法:在路由的路径配置里 /路径/:参数名 -->
<router-link to="/part/114514">朋友</router-link>
在接收参数的组件内
<!-- query的传参接收参数写法: $route.query.参数名 -->
<div>params的传参:{{$route.query.name}}</div>
<!-- params的传参接收参数写法: $route.params.参数名 -->
<div>query的传参:{{$route.params.id}}</div>
注意:用params传参还需要在路由的配置表中在所要接收参数的组件路径后添加 /:id
<script>
// params写法: /路径/:参数名
{ path: '/part/:id',
component: Part }
</script>
tips:this.$router.push方法中,有着不同的写法
方式1, 直接 path 作为字符串传入
this.$router.push('/my')
方式2 传入一个对象, 其中带有 path 属性
this.$router.push({
path: '/my', //后面可以拼接?+键值对,query的传参本质也是拼接,所以path拼接传参后面可以不需要再加个query
name: 'abc', //name属性, 需要在路由中预先配置
query:{
'参数名':值
},
params:{
'参数名':值
}
})
其中,path和name属性二选一,query和params看传参方式也是二选一。但是使用path会忽略params
4.嵌套路由
嵌套路由是在所要嵌套的组件路径配置表里添加children对象
// routes 配置中添加
{
// 所要嵌套的父路由
path: '/find',
component: Find,
// 嵌套子路由
children: [
// 依旧是 path 跟 component 的配对
// 不要加斜杠, 因为需要改上一层拼接在一起
{
path: 'ranking',
component: Ranking
},
{
path: 'recommend',
component: Recommend
},
{
path: 'songlist',
component: SongList
},
]
},
路由表配置完成后在父路由里设置嵌套子路由挂载点
<router-view></router-view>
5.导航守卫
导航守卫类似于ajax中的拦截器
// router 创建实例之后
// 可以往这个 router 路由实例添加导航守卫(路由守卫)
// 全局前置, 所有页面跳转之前都会经过
router.beforeEach((to, from, next)=>{
// 拦住了必须放行, 默认这个函数可以接收到三个参数
// to 要去往哪, from 从哪里来, next 放行回调函数
next() //如果没有next这个函数,那么页面跳转后就会一直不显示内容,所以next回调函数是必须添加的
}
})
十一、vant组件库
引入vant组件库
1.安装vant组件库
npm i vant@2 (使用vue几就装对应的版本)
2.在main.js中进行全局引入
全部引入(将整个组件库全部引入,会影响性能)
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
按需引入(需要用到那个组件就引入那个,有利于提高性能)
import { Button } from 'vant';
import 'vant/lib/button/style';
Vue.use(Button);
tips:.native,事件修饰符,可以在组件上添加原生的事件
十二、vuex
1.vuex的概念
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 总而言之就是一个声明全局变量的地方,使得各个组件都可以访问这个全局变量
2.vuex的导入和使用
// 1.下载vuex npm i vuex -S
// 2.导入
import Vuex from 'vuex'
// 3.注册
Vue.use(Vuex)
// 4.实例化vuex
const store = new Vuex.Store({
// 配置项
})
new Vue({
// 5.挂载
store,
router,
render: h => h(App)
}).$mount('#app')
3.state和getters
在main.js中的store进行配置
<script>
const store = new Vuex.Store({
state: { // 专门用来声明全局变量的地方
count: 0,
list: [1, 4, 5, 3, 8, 9, 2, 6, 7]
},
getters: { // getters声明的变量是从state派生出来的,例如filterList就是从state的list属性所派生而来的
filterList(state) {
return state.list.filter(value => value % 2 !== 0)
}
}
})
</script>
在app.vue里
<template>
<div>
<h1>{{ list }}</h1>
<h1>{{ filterList }}</h1>
</div>
</template>
<script>
// 导入辅助函数(具名导入)
import { mapState, mapGetters } from "vuex";
export default {
computed: {
// 读取store/getters里的属性优化写法
// list/filterList() {
// return this.$store.state.count
// }
// 辅助函数更优化写法
...mapState(["list"]),
...mapGetters(["filterList"])
}
};
</script>
<style>
</style>
tips:state和getters不使用辅助函数在页面上插入值写法为$store.state/getters.属性名
4.actions和mutations
在main.js中的store进行配置
<script>
const store = new Vuex.Store({
mutations: { // mutations是专门用来修改state中的变量的对象(属性)
addCount(state, num) {
state.count += num
}
},
actions: { // actions就是可以通过异步操作,调用mutations中的函数,从而修改state中的变量。
asyncAdd(store, num) { //actions默认的参数和其他几个属性的默认参数不同,是store
setInterval(() => {
store.commit('addCount', num)
}, 1000);
}
},
})
</script>
在app.vue里
<template>
<div>
<h1>{{ count }}</h1>
<!--mutations的使用 -->
<!--直接在点击事件上写业务代码-->
<button @click="$store.commit('addCount', 10086)">增加</button><br />
<!--声明函数去处理业务代码-->
<button @click="sumAdd(100)">+100</button><br />
<!--辅助函数写法-->
<button @click="addCount(50)">+50</button>
<!-- actions的使用(与上述说明一致) -->
<button @click="$store.dispatch('asyncAdd', 1)">一秒后加1</button><br />
<button @click="timeLose">一秒后加5</button><br />
<button @click="asyncAdd(8)">一秒后加8</button>
</div>
</template>
<script>
// 导入辅助函数(具名导入)
import { mapState,mapMutations, mapActions } from "vuex";
export default {
computed: {
...mapState(["count"]),
},
methods: {
// 函数写法
sumAdd(num) {
this.$store.commit("addCount", num);
},
timeLose() {
this.$store.dispatch('asyncAdd', 5)
},
// 辅助函数写法
...mapMutations(["addCount"]),
...mapActions(['asyncAdd'])
},
};
</script>
<style>
</style>
tips1:辅助函数所用数组包裹起来的变量名,必须与在该属性下声明的变量同名
tips2:mutations不用辅助函数去调用方法的写法:$store.commit('变量名', 参数值);
tips3: ations不用辅助函数去调用方法的写法:$store.dispatch('变量名', 参数值)
5.modules
<script>
const store = new Vuex.Store({
state:{}
getters:{ // 模块里的state属性值可以通过外层的state进行访问,因为模块看似是分开写了,但是里面的对象还是挂载在最外层的四个对象里
access: state => state.user.access
}
...
modules: { // modules可以将这四个属性进行模块化,以便更好管理store实例,而且代码也显得不那么臃肿
user:{
namespaced: true, // 当加上锁时,就不能通过全局的store.commit/dispatch('函数名',变量)来调用模块里的mutations/actions方法。
state:{ // 相当于在外层state:{user:{access:1}}
access: 1
},
mutations:{
// 这里的state是admin里的state
cgeAccess: state => {state.access = 10}
},
actions:{},
getters:{}
}
}
})
</script>
在app.vue的使用
<template>
<div>
<!--未上锁时,全局调用模块内的方法可以直接调用,因为是挂载在最外层的对象上-->
<button @click="$store.commit('cgeAccess')">通过全局调用模块里的mut修改(未上锁)</button>
<!--如果上锁了,全局调用模块内的方法就必须通过$store.commit/dispatch('模块名/方法名')的方式来调用-->
<button @click="$store.commit('admin/cgeAccess')">通过全局调用模块里的mut修改(上锁)</button>
<button @click="changeAccess">通过辅助函数调用模块里的mutations修改</button>
<button @click="addCount(10)">通过辅助函数调用全局的mutations修改</button>
</div>
</template>
<script>
import { mapGetters,mapMutations } from "vuex";
export default {
computed: {
...mapGetters(["name", "access",'filterList'])
},
methods: {
// 通过辅助函数调用全局的mutations修改(上锁),建议一次解构一个模块
...mapMutations('admin',['changeAccess'])
// 模块结构后并不会影响最外层函数解构
...mapMutations(['addCount'])
}
};
</script>
tips1:外层数据用外层的方法进行操作和调用,模块里的数据就用模块里的方法进行操作和调用
tips2:全局的actions对象的内置形参store与store实例有所不同,但是还是可以访问里面的变量和方法
tips3:模块上锁只是将全局调用模块里的方法上锁了,但是模块state里的数据还是一样在全局能访问
总结:vuex就是围绕着state里的数据进行操作,getters是state派生的数据,mutations作用是通过同步操作来修改state里的数据,actions作用是通过异步操作来修改state里的数据。而modules则是将state的数据进行模块化,使得每个模块通过自身的getters、mutations、actions对象去操作state数据,做到数据方便管理和结构清晰