《vue3从零搭建一个后台》(四)、项目的样式 及 Vue-router 和vuex的配置

配置环境的最后一环。

配置UI

这里选用了Element Plus,忽略掉项目样式的设计时间。用现成的。
Element Plus,一套为开发者、设计师和产品经理准备的基于 Vue 3.0 的桌面端组件库。官方文档=>Elment Plus
使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。

npm install element-plus --save   //npm 配置 淘宝源,下载效果更佳,百度教程
// -s  安装。项目必须包。
下载完成

进入入口文件main.js 引入它

import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 路由
import store from './store' // vuex
// element 组件这里全部引入,也可定制按需引入,如只要button、table等用到的组件
import ElementPlus from 'element-plus'
// 所有组件相关的样式
import 'element-plus/lib/theme-chalk/index.css'
// 挂载
createApp(App).use(store).use(router).use(ElementPlus).mount('#app')

配置vue-router

这三个文件是启动时暂时的页面相关文件,也可以不删。留着。


删除项目创建自带的三个Vue文件

App.vue去掉注释部分

<template>
  <!-- <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div> -->
  <router-view />
</template>

<style>

然后创建view/home/index.vue


该文件用于接下的Vuex的使用
<template>
  <el-row>
    <el-col>欢迎来到漂流城!</el-col>
  </el-row>
</template>

<script>
export default {
  name: 'Home'
}
</script>

进到router/index.js

import { createRouter, createWebHistory } from 'vue-router'
/**
 具体参数可以百度官方网查看
 */
const routes = [
  {
    path: '/', // localhost:7779 获取 home/inde.vue页面
    name: 'Home',
    component: () => import('@/views/home/index')
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

npm run serve //项目跑起来

vue-router的作用展示结束

配置Vuex

vuex管理项目的一些状态(类似全局变量)
官方文档:Vuex
进入store/index.js 查看vuex的基本构成

import { createStore } from 'vuex'

export default createStore({
  state: {
    // 状态变量
  },
  mutations: {
    // 状态更改的地方
    // 这里只能进行同步代码
  },
  actions: {
    // 异步操作mutations (变相让mutation支持异步)
  },
  modules: {
    // vuex 模块化
  }
})

以下展示Vuex4的一些用法。会的可以忽略

State

State对象就包含了项目全部状态(未分模块)

使用:
//在state 定义一个状态(可以理解为项目全局变量)
state: {
    // 状态变量
    name: '麦克斯'
  }
// home/index.vue
<template>
  <el-row>
    <el-col>{{ name}},欢迎来到漂流城!</el-col>
  </el-row>
</template>
// 以下 是 三种 获取 state 调用,结果都一样
<script>
export default {
  name: 'Home',
  data() {
    return {
      name: this.$store.state.name  // 定义一个变量来获取状态,名字随意
    }
  },
}
</script>
<script>
//computed监听
export default {
  name: 'Home',
  computed: {
    name() {
      return this.$store.state.name
    }
  }
}
</script>
<script>
//也可以引入辅助函数mapState 辅助函数,更方便管理状态
import { mapState } from 'vuex'
export default {
  name: 'Home',
  //computed: mapState({
   // name: state => state.name
  //})    // 这里是传对象
  //computed: mapState([
    //'name'
  //]) // 这里是传数组,'name' 会被映射为state => state.name
   computed: {
    ...mapState([
      'name'
    ]) // 用一个工具函数将多个对象合并为一个
  }
}
</script>

ctrl+c 保存index.vue。在回到网页看看结果


成功获取到了状态

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
进入store/index.js 添加

 state: {
    // 状态变量
    name: '麦克斯',
    count: 0
  },
  mutations: {
    // 状态更改的地方
    // 这里只能进行同步代码
    ADD(state) {
      state.count++
    },
   // 支持带参数
    ADDS(state, num) {
      state.count += num 
    }
  },

调用的2个方式,跟state类似

<template>
  <el-row>
    <el-col>{{ name }},欢迎来到漂流城!</el-col>
    <el-col>{{ count }}</el-col>
    <el-button @click="ADD">count+1</el-button>
    <el-button @click="ADDS(10)">count+10</el-button>
    <el-button @click="ADDSS()">count+1</el-button>
  </el-row>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'Home',
  computed: {
    ...mapState([
      'name',
      'count'
    ])
  },
 // 第一种
  methods: {
    add() {
      this.$store.commit('ADD')
      this.$store.commit('ADDS', 10)
    }
  }
// 第二种
methods: {
    ...mapMutations([
      'ADD', // 将 `this.ADD()` 映射为 `this.$store.commit('ADD')`
      // `mapMutations` 也支持传参:
      'ADDS' // 将 `this.ADDS(amount)` 映射为 `this.$store.commit('ADDS', amount)`
    ]),
    ...mapMutations({ //自定义名称
      ADDSS: 'ADD' // 将 `this.addss()` 映射为 `this.$store.commit('ADD')`
    })
  }
}
</script>

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
    进入 store/inde.js 加入以下代码
actions: {
    // 异步操作mutations (变相让mutation支持异步)
    add (context) {
      context.commit('ADD')
    }
  },
// context 具有 store的属性 ,context.commit 提交一个 mutation,
//或者通过 context.state 和 context.getters 来获取 state 和 getters。
//利用结构写法,简化
actions: {
    // 异步操作mutations (变相让mutation支持异步)
    // 可以和 mutation 同名,
    add({ commit }) {
      commit('ADD')
    }
    // 带参数(一般为对象,可带参数更多)
    adds({ commit }, data) {
      commit('ADDS', data.num)
    }
  },

允许异步

actions: {
  add({ commit }) {
    setTimeout(() => {
      commit('ADD')
    }, 1000)
  }
}

页面调用Action

store.dispatch('add')
 // 带参数(一般为对象)
store.dispatch('adds', {
  amount: 10
})
<template>
  <el-row>
    <el-col>{{ name }},欢迎来到漂流城!</el-col>
    <el-col>{{ count }}</el-col>
    <el-button @click="ADD">count+1</el-button>
    <el-button @click="ADDS(10)">count+10</el-button>
    <el-button @click="ADDSS">count+1</el-button>
    <el-col>Action:</el-col>
    <el-button @click="add">add</el-button>
    <el-button @click="adds({ num: 10 })">adds(10)</el-button>
    <el-button @click="addss">addss+1</el-button>
  </el-row>
</template>

<script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  name: 'Home',
  computed: {
    ...mapState([
      'name',
      'count'
    ])
  },
  // methods: {
  //   add() {
  //     this.$store.commit('ADD')
  //   }
  // }
  methods: {
    ...mapMutations([
      'ADD', // 将 `this.ADD()` 映射为 `this.$store.commit('ADD')`
      // `mapMutations` 支持带参数
      'ADDS' // 将 `this.ADDS(amount)` 映射为 `this.$store.commit('ADDS', amount)`
    ]),
    ...mapMutations({
      ADDSS: 'ADD' // 将 `this.ADDSS()` 映射为 `this.$store.commit('ADD')`
    }),
    ...mapActions([
      'add', // map `this.add()` to `this.$store.dispatch('add')`
      // `mapActions` 待参数
      'adds' // map `this.adds(amount)` 映射为 `this.$store.dispatch('adds', amount)`
    ]),
    ...mapActions({
      addss: 'ADD' // map `this.addss()` 映射为 `this.$store.dispatch('add')`
    })
  }
}
</script>

以上就是vuex 简单调用,实际上根据项目的需求,状态也会随之变多,维护起来也是挺头疼的。
为了解决这个问题,Vuex 允许我们将 store 分割成模块(module)。
每个模块拥有自己的 state、mutation、action、getter

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state

模块化的使用例子:
进入 store/index.js。删除之前的所有内容,也可以保存方便 复习

import { createStore } from 'vuex'

const dog = {
  namespaced: true, // 需要开启命名空间 识别这个module
  state: () => ({
    name: '麦克斯',
    sex: '6'
  }),
  mutations: {},
  actions: {}
}

export default createStore({
  modules: {
    dog // es6语法 ===  dog:dog   同名可以简写
  }
})

state状态的获取
进入home/index.vue,删除之前的内容

<template>
  <el-row>
    <el-col>----信息----</el-col>
    <el-col>name2: {{ name2 }}</el-col>
    <el-col>年龄2: {{ sex2 }}</el-col>
    <el-col>name1: {{ name1 }}</el-col>
    <el-col>年龄: {{ sex }}</el-col>
  </el-row>
</template>

<script>
import { mapState } from 'vuex'
// 模块化的调用
export default {
  name: 'Home',
  data() {
    return {
      // 第一种方式获取
      name1: this.$store.state.dog.name
    }
  },
  computed: {
    // 第二种方式获取   对象
    ...mapState({
      name2: state => state.dog.name
    }),
    // 第三种方式获取   对象
    ...mapState('dog', {
      sex2: state => state.sex
    }),
    // 第四种 方式,  数组
    ...mapState('dog', [
      'sex'
    ])
  }
}
</script>

</script>
方式和上面差不多,主要是模块的引用

mutations的调用
store/index.js 加入

...
   mutations: {
    CHANGE_NAME(state) {
      state.name = '旺财'
    },
    CHANGE_SEX(state, num) {
      state.sex = num
    }
  },
...

home/index.vue 加入

//teamplate
    <el-col>--- Mutations ---</el-col>
    <el-col><el-button @click="change">Change()</el-button></el-col>
    <el-col><el-button @click="CHANGE_NAME">CHANGE_NAME()</el-button></el-col>
    <el-col><el-button @click="CHANGE_SEX(10)">CHANGE_SEX(10)</el-button></el-col>
    <el-col><el-button @click="change2">change2()</el-button></el-col>
// script
methods: {
    // 第一种
    change() {
      this.$store.commit('dog/CHANGE_NAME')
    },
    // 第二种
    ...mapMutations('dog', [
      'CHANGE_NAME', // 将 `this.CHANGE_NAME()` 映射为 `this.$store.commit('dog/CHANGE_NAME')`
      // `mapMutations` 也支持传参:
      'CHANGE_SEX' // 将 `this.CHANGE_SEX(amount)` 映射为 `this.$store.commit('dog/CHANGE_SEX', amount)`
    ]),
    // 第三种
    ...mapMutations('dog', { // 自定义名称
      change2: 'CHANGE_NAME' // 将 `this.change2()` 映射为 `this.$store.commit('dog/CHANGE_NAME')`
    })
  }

action 的模块化后的调用
store/index.js 加入

actions: {
    changeName({ commit }) { 
      commit('CHANGE_NAME')
    },
   changeSex({ commit }, data) {
      commit(' CHANGE_SEX', data.num) // 通常传入一个对象,方便传递更多参数
    }
  }

login/index.vue加入

//teamplate
<el-col>--- Action ---</el-col>
    <el-col><el-button @click="change3">Change()</el-button></el-col>
    <el-col><el-button @click="changeName">changeName</el-button></el-col>
    <el-col><el-button @click="changeSex({num: 10})">changeSex({num: 10})</el-button></el-col>
    <el-col><el-button @click="change4">change4()</el-button></el-col>
//script
methods: {
    // 第一种
    change3() {
      this.$store.dispatch('dog/changeName')
      this.$store.dispatch('dog/changeSex', { num: 10 })
    },
    // 第二种
    ...mapActions('dog', [
      'changeName',
      'changeSex'
    ]),
    // 第三种,自定义方法
    ...mapActions('dog', {
      change4: 'changeName'
    })
  }

getters

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
store/index.js 加入getters

...state{
    speark: '旺旺'  //加入一个新的状态
}
...mutations
...actions
getters: {
   // speark: state => state.speark,
    speark: state => {
        //这里可以对状态进行一些操作,如数组过滤等.
        return state.speark
    }
}

getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:

// 对应getter 对象里的属性。可以和state里的同名方便记 
store.getters.name// -> [{name: '麦克斯'...}]

home/index.vue 使用getters

computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
   ...mapGetters('dog', [ // 直接映射
      'speark' // this.speark 会被映射为store.getters.speark
    ]),
    ...mapGetters('dog', { // 自定义变量
      speark1: 'speark' // this.speark1 会被映射为store.getters.speark
    })
  }
//由于模块化了。所以加入了模块写法。

好了,到这来 Vuex 的普遍用法介绍完了。更深的高级写法可以去看官网学习。

这里的状态是响应式的。不管在那个模板变动了这些状态。相关视图都会 更新。

项目结构的Vuex 配置

这里配置项目的Vuex 结构。以上联系的文件可以保留。方便回忆。
目录结构
src/store/index.js、
src/store/getters.js、
src/store/modules/app.js、


目录结构

app.js 某个模块

const state = {
  name: 'dky后台'
}

const mutations = {}

const actions = {}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

整体getters
getters.js

const getters = {
  name: state => state.app.name,
}
export default getters

index.js

import { createStore } from 'vuex'
import getters from './getters'
// webpack Api 它会遍历文件夹中的指定文件,然后自动导入,不用都import
const modulesFiles = require.context('./modules', true, /\.js$/)

const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'  $1 即 app
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = createStore({
  modules,
  getters
})

export default store

至此,模块化配置结束。有新的模块直接在module问价夹创建 moduleName.js 定义模块内 state,mutations,action 即可。调用和之前一样

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容