vuex
什么是vuex
状态管理器
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。因为我们是MVVM框架,view取决于我们model(数据),view如何展示称为元素状态,那么model数据也就是状态数据。
vuex是基于flux设计原理实现的一个单向数据流状态管理器,但他不是唯一的状态管理器,还有个pinia
管理状态数据的库
Vuex特点
全局数据:
全局变量会导致全局数据污染,所以vuex一定是一个闭包
集中式存储管理应用的所有组件的状态
实现数据共享:简化Vue组件间通讯,可跨组件(子传父、父传子)
eventBus:两个组件必须同时存在,并且监听要早于触发:数据不会缓存
provide+inject:修改数据不能在子组件中进行,可以用computed缓存
父子传子:不能跨组件传值,只能是父子关系才可以
数据可预测化:使用发布订阅机制来实现;保证状态以一种可预测的方式发生变化(有序进行数据存储获取)
核心概念与原理
1. state:
页面状态管理容器对象。集中存储Vue components状态数据
定义和初始化全局需要托管的数据,因为托管的数据是状态,所以这个属性是state
2. mutations:
修改数据/扭转状态数据
状态改变操作方法,由actions中的commit(‘mutation 名称’)来触发。
是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。
- 修改数据的方法不能为异步方法,为什么?
因为异步函数,什么时候结束,不清楚,但是setToken方法执行以后,会立刻发布更新消息,那么这样,发布出去的消息有问题,数据更新还没有执行完成。
而且flux设计原理,规定mutation必须为一个纯函数--输出必须完成依赖输入,不能修改外部数据
3. commit:
状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
是一个提交数据的方法
4. actions:
操作行为处理模块,执行数据处理的动作属性。这个动作不可以修改数据,因为修改数据只能在mutations可以。所以它获取到异步数据后需要一个commit方法进行数修改。
actions可以定义异步任务,由组件中的$store.dispatch('action 名称', data1)来触发。然后由commit()来触发mutation的调用 , 间接更新 state。
5. dispatch:
操作行为触发方法,是唯一能执行action的方法。
6. getters:
state对象读取方法,取数据。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。
getters和state是两个不同的模块,所以数据不能共享,那么只有这个方法把值传递进来
getters是获取数据的getter方法
因为getter方法传递给vuex以后,他还需要加工,所以可以把state传递进来
7.this.$store
this.$store中只有三个属性可用:getters、commit、dispatch,其他都是 _ 开头的私有属性
getters是获取数据的getter方法
commit提交数据,定义接口commit('type提交给这个方法中去',提交的数据),是一个提交数据的方法
dispatch调遣/派遣一个动作,即actions
使用步骤
1.下载安装
npm install vuex@4.0.2 --save
npm install vuex@next --save
2.在src下的main.js引入、注册
//src/main.js
import { createApp } from 'vue'
import App from './views/index.vue'
import Vuex from 'vuex'
//Store这个方法/类执行以后会得到一个Store实例
const store = new Vuex.Store({
state:{//定义和初始化全局需要托管的数据,因为托管的数据是状态,所以这个属性时state
token: 100,
userInfo: {}
},
getters:{
mytoken(_state) {
return _state.token
},
userInfo: _state => _state.userInfo
},
// 执行数据处理的动作属性中去执行--dispatch方法--调遣、派遣一个动作
actions: {
// 这个动作没有办法执行数据修改,因为数据修改只有mutations可以,所以它获取到异步数据以后需要一个commit方法进行数据修改
async getUserInfo(_store, id) {
let result = await ajax(id)
_store.commit('setUserInfo', result)
}
},
mutations: {
setToken(_state, _token) {
// 修改的是state的数据,这里没有state对象,那么只有这个方法把state传递进来
// 第二个参数才是我们传递的数据
_state.token = _token
},
setUserInfo(_state, _userInfo) {
console.log('----------------- 赋值', _userInfo)
_state.userInfo = _userInfo
}
}
})
// 也需要注入store
createApp(App).use(store).mount('#root')
3.主页 views/index.vue 获取后显示值
//views/index.vue
<template>
<div class="box">
<h3>系统的名字</h3>
<p>
当前的token值:{{$store.getters.mytoken}}
</p>
<Home/>
</div>
</template>
<script>
import Home from './Home.vue'
export default {
components: { Home },
created() {
console.log(this.$store.getters.mytoken)
}
}
</script>
4.首页 主页的子组件 src/views/Home.vue 修改上面首页token的值 commit(传递值)
//src/views/Home.vue
<template>
<div class="box">
<hr>
<h4>首页 -- 欢迎您 -- {{name}}</h4>
<p>
<button @click="changeToken">修改token数据</button>
</p>
<Child/>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: { Child },
computed: {
name() {
// console.log('userInfo-----',this.$store.getters.userInfo);
return this.$store.getters.userInfo.name
}
},
methods: {
changeToken() {
let value = this.$store.getters.mytoken
this.$store.commit('setToken', value + 1)
}
}
}
</script>
5.首页子组件 传递值给首页的欢迎您
//src/views/Child.vue
<template>
<div class="box">
<hr>
<h5>这里是Home的子组件</h5>
<p>
名字: <input v-model='myname' type="text">
</p>
<p>
<button @click="asyncFunc">异步请求数据修改</button>
</p>
</div>
</template>
<script>
export default {
data() {
return {
myname: ''
}
},
methods: {
asyncFunc() {
this.$store.dispatch('getUserInfo', this.myname)
}
}
}
</script>
使用步骤
1.下载安装:
npm install vuex@4.0.2 --save 或 npm install vuex@next --save
2.新建实现store文件夹 index.js文件
import {createStore} from 'vuex' //引入vuex,解构createStore
const store = createStore({ //使用createStore
state:{ //状态
count:0 //状态数据
},
mutations:{ //方法
//state:状态,第二个及以后的参数是传入的参数用逗号隔开
PLUS(state,user){ //大写_大写
state.count++
//stare.count = user
},
MINUS(state){
state.count--
}
},
actions:{ //方法
plus({commit}){ //commit方法调用
commit('PLUS') //mutations下的方法名
},
minus({commit}){
commit('MINUS')
}
},
getters:{ //获取值
num:(state)=>state.count
}
})
export default store
3. main.js文件引入集成到vue
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store' //store文件下的store
const app = createApp(App)
app.use(router)
app.use(store) //集成
app.mount('#app')
4.使用vuex
<template>
<div>
<p>显示vuex状态count : {{num}}</p> <!--显示状态数据-->
<button type="button" @click="onPlus">加一</button> <!--加一操作 触发方法操作store数据-->
</div>
</template>
<script>
export default {
//methods - 创建方法
methods:{
onPlus(){ //actions里的定义的名字,
this.$store.dispatch('plus',参数) //调用方法.将参数传回store
}
},
computed:{
num(){
return this.$store.getters.num
}
}
}
</script>
...map 辅助函数
mapGetters 直接获取getters值
mapActions 直接操作行为处理
下载、创建、引入集成与前面一样 ,使用方法有些不同
使用
1.在组件里引入 .vue
<script>
import { mapGetters,mapActions } from 'vuex' //引入
</script>
<template>
<div>
<p>显示vuex状态count : {{ num }}</p>
<button type="button" @click="minus">减一</button>
</div>
</template>
2.使用 .vue
export default {
data() {
return {}
},
//methods - 创建方法
methods: {
// onMinus() {
// this.$store.dispatch('minus')
// }, 上下实现的效果一样
// ...mapActions({
//计算属性名: vuex中actions定义名称
// onMinus:'minus'
// }) 计算属性名随意取,如果和actions名一样就用下面这个方式
...mapActions(['minus']) //当计算属性名和vuex中getters定义名称相同时,使用如下方式实现
},
computed: {
// num(){
// return this.$store.getters.count
// },
// ...mapGetters({
//计算属性名: vuex中getters定义名称
// num:'count'
// })
...mapGetters(['num']),
},
}
持久化存储
1.安装vuex-persistedstate插件
npm install vuex-persistedstate --save
2.在store中的index.js中引入
该插件默认持久化所有state,当然也可以指定需要持久化的state:
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate' //引入持久化 哪个vue需要持久化就在哪里引入
const store = createStore({
plugins: [
createPersistedState({
storage: window.sessionStorage, //默认 修改存储的状态
key: 'userkey', //上下两个可以不写 默认key为vuex
reducer(data) {
return {
// 设置只储存state中的myData 不设置为存储所有
myData: data.myData
}
}),
],
})
Module模块化
应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter
1.在store文件下创建modules文件夹,文件夹内创建各种所需要处理的模块
//cart.js
const cart = { //在cart这个命名空间下
namespaced: true, //命名空间指定模块名
state: {
list: [],
},
mutations: {
ADD_Cart(state, product) {
state.list.push(product)
},
},
actions: {
addCart({ commit }) {
commit('ADD_Cart')
},
},
getters: {
// list:state=>state.list
list(state) {
return state.list
},
},
}
export default cart
store中的index.js
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import user from './modules/user' //导入user.js
import cart from './modules/cart' //导入cart.js
const store = createStore({
modules: { //集成模块
user,
cart,
}
})
export default store
//Home.vue
import { mapGetters } from "vuex";
export default {
data() {
return {
// user: null,
}
},
computed:{
user(){
return this.$store.getters['cart/list'] //cart这个命名空间下的list
}
// ...mapGetters(['user'])
},
elementPlus UI组件库
1.下载安装组件库
NPM****
$ npm install element-plus --save
# Yarn
$ yarn add element-plus
# pnpm
$ pnpm install element-plus
2. 按需导入 自动按需导入推荐
首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件
npm install -D unplugin-vue-components unplugin-auto-import
3.vite.config.js 配置插件
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
Icon图标下载
npm install @element-plus/icons-vue
按需导入
直接通过设置类名为 el-icon-iconName
来使用即可
//Login.vue
<script>import {User} form '@element-plus/icons-vue'</script>
<el-icon> <User /> </el-icon>
<script>export default {
components: {
User,
Lock,
},
}</script>
//或者
<i class="el-icon-share"></i>
<i class="el-icon-delete"></i>
<el-button type="primary" icon="el-icon-search">搜索</el-button>