Vuexms項(xiàng)目文檔

1.起步

1.1.前言

這篇文檔是跟隨騰訊課堂課程:前端教程vuex實(shí)現(xiàn)管理系統(tǒng),給自己寫的課堂隨筆,僅作記錄作用。建議先去vuex官網(wǎng)了解一些基本知識(shí)再開始。

本文檔可能會(huì)出現(xiàn)數(shù)據(jù)對(duì)不上的問題,原因是視頻中有不斷更改數(shù)據(jù),所以后面會(huì)對(duì)之前的數(shù)據(jù)庫(kù)或者頁(yè)面元素作出調(diào)整。然后我自己嘗試解決了部分工具版本上的問題,很多地方記錄的不詳盡,推薦看視頻。

主要用到的工具/包有:vue, vuex, npm, nodemon, mysql, element-ui, axios

1.2.初始化項(xiàng)目

  1. 打開項(xiàng)目位置文件夾,在地址欄輸入cmd打開當(dāng)前目錄的控制臺(tái),輸入以下代碼:

    vue init webpack vuexms
    
    控制臺(tái)顯示圖
  2. 繼續(xù)在控制臺(tái)輸入指令以安裝相關(guān)包:

    cd vuexms
    npm i
    
    初始完成的文件目錄
  3. 試著運(yùn)行我們的初始項(xiàng)目:

    npm run dev
    
    顯示

控制臺(tái)表明我們的項(xiàng)目運(yùn)行在了http://localhost:8080,打開就能看到默認(rèn)的初始界面。

1.3.個(gè)性化

  • 打開vuexms\src\App.vue,這是我們項(xiàng)目的路由出口,同時(shí)刪掉<template>中的img標(biāo)簽和<style>中的所有內(nèi)容:
<!-- 這是默認(rèn)的主頁(yè)面logo圖 -->
<img src="./assets/logo.png"> 
  • 打開vuexms\src\components\HelloWorld.vue,這是路由指示的主界面,刪除<template>中的標(biāo)簽。同時(shí),將文件名改為我們需要的login.vue,然后更改src\router\index.js中的相關(guān)代碼。

    import Vue from 'vue'
    import Router from 'vue-router'
    
    // 引入組件
    import login from '@/components/login'
    
    // 注冊(cè)路由
    Vue.use(Router)
    
    // 導(dǎo)出路由
    export default new Router({
      routes: [
        {
          path: '/login',
          name: 'login',
          component: login
        }
      ]
    })
    

2.實(shí)現(xiàn)登錄頁(yè)

2.1.使用Element

官網(wǎng)地址:Element

  1. 切換回控制臺(tái),Ctrl+C暫時(shí)停止服務(wù)器。

    npm i element-ui -S
    
  2. 找到src目錄 下的main.js,添加以下代碼

    // 引入
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    
    // 注冊(cè)
    Vue.use(ElementUI);
    
  3. 測(cè)試是否注冊(cè)成功,在login.vue中加入以下代碼,重啟服務(wù)器:npm run dev,如果頁(yè)面中正常加載出了按鈕表示注冊(cè)成功。

    <el-button>按鈕</el-button>
    

2.2.使用組件

  1. element-ui官網(wǎng)找到合適的表單登錄組件,分別將里面的HTML代碼和Javascript代碼放到對(duì)應(yīng)頁(yè)面,我們這里是login.vue。

  2. 我們會(huì)加入css代碼讓頁(yè)面更加美觀,在這之前應(yīng)該重置樣式來避免一些錯(cuò)誤??梢栽?code>static中新建css文件夾,然后放入合適的reset.css,然后再在index.html中引入:

    <!-- reset.css -->
    <link rel="stylesheet" href="./static/css/reset.css">
    
  3. 自定義數(shù)據(jù)和樣式。


    登陸窗口

2.3.axios

安裝:

npm i axios -S

main.js中引入:

// 引入 axios
import axios from 'axios'
// 掛載到 Vue 的原型上
Vue.prototype.axios = axios

login.vue中檢測(cè):

submitForm(formName) {
  this.$refs[formName].validate((valid) => {
    if (valid) {
       // 確認(rèn)是否能打印出信息   
       console.log(this.axios)
     } else {
       console.log('error submit!!');
       return false;
     }
  });
},

向后臺(tái)發(fā)送數(shù)據(jù)并得到響應(yīng):

this.axios.post('/api/checklogin', {
  username: _this.loginForm.username,
  password: _this.loginForm.password
})
.then(response => {
  console.log('接收后端響應(yīng)的數(shù)據(jù)')
})

2.4.express搭建服務(wù)器

實(shí)現(xiàn)登錄,需要從服務(wù)器獲取數(shù)據(jù),所以我用 express 搭建了一個(gè)。

  1. 確保全局安裝了 express,4.X 后的版本需要安裝 express-generator。

    npm install -g express
    npm install -g express-generator
    

    在環(huán)境變量中添加 path: <u>C:\Users\admin\AppData\Roaming\npm</u>。

  2. 項(xiàng)目同級(jí)目錄打開cmd工具:

    express server -e
    cd server
    npm install
    
  3. 打開 server 中的 app.js 添加:

    // 監(jiān)聽端口
    app.listen(888, () => {
      console.log('888端口的服務(wù)器已經(jīng)啟動(dòng)...')
    })
    

    在 server\routes\index.js 中設(shè)置:

    // 接收請(qǐng)求
    router.post('/checklogin', (req, res) => {
      // 接收用戶名和密碼
      let { username, password} = req.body;
      console.log(username, password)
      // 發(fā)送響應(yīng)
      res.send('服務(wù)器數(shù)據(jù)')
    })
    

    因?yàn)槭强缬蛘?qǐng)求,在 vuexms\config\index.js 中設(shè)置:

    proxyTable: {
      '/api': {
        target: 'http://localhost:888', // 接口的域名
        changeOrigin: true, // 如果是跨域請(qǐng)求,需要配置此項(xiàng)
        pathRewrite: {
          '/api': ''
        }
      }
    }
    
    • 項(xiàng)目控制臺(tái)重啟項(xiàng)目npm run dev

    • 服務(wù)器控制臺(tái)啟動(dòng)服務(wù)器node app

    • 打開項(xiàng)目頁(yè)面,輸入帳號(hào)密碼提交后檢查服務(wù)器控制臺(tái)和網(wǎng)頁(yè)響應(yīng)數(shù)據(jù):

      服務(wù)端收到數(shù)據(jù)
      服務(wù)器數(shù)據(jù)

    至此說明項(xiàng)目和服務(wù)器已經(jīng)聯(lián)通了,接下來需要比對(duì)數(shù)據(jù)庫(kù)進(jìn)行登錄驗(yàn)證。

2.5.連接數(shù)據(jù)庫(kù)

首先我們需要?jiǎng)?chuàng)建一個(gè)數(shù)據(jù)庫(kù),在 計(jì)算機(jī) -> 管理 -> 服務(wù) 中啟動(dòng) mysql,新開一個(gè) cmd 控制臺(tái)窗口:

  1. 連接mysql

    mysql -hlocalhost -uroot -proot
    
  2. 新建數(shù)據(jù)庫(kù)

    show databases;
    create database vuexms;
    use vuexms;
    
  3. 新建表

    create table users (
      id int primary key auto_increment,
      username varchar(50),
      password varchar(50),
      realname varchar(50),
      age int,
      idType varchar(50)
    );
    desc users;
    
  4. 插入數(shù)據(jù)

    insert into users(username, password, realname, age, idType) value('xiaoyao', '123456', '李逍遙', '20', '00001');
    insert into users(username, password, realname, age, idType) value('linger', '123456', '趙靈兒', '18', '00002');
    select * from users;
    

然后通過 node 連接數(shù)據(jù)庫(kù):

  1. 在服務(wù)器控制臺(tái)安裝mysql包

    npm i mysql -S
    
  2. 在 server\routes 路徑下新建 conn.js 文件:

    // 引入mysql
    var mysql = require('mysql')
    
    // 創(chuàng)建連接
    var connection = mysql.createConnection({
      host     : 'localhost',
      user     : 'root',
      password : '123456',
      database : 'vuexms'
    });
    
    // 暴露出去
    module.exports = connection
    
  3. 在同路徑的 index.js 中:

    // 引入連接數(shù)據(jù)庫(kù)模塊
    const connection = require('./conn')
    
    // 連接數(shù)據(jù)
    connection.connect(() => {
      console.log('數(shù)據(jù)庫(kù)連接成功!')
    })
    
    router.post('/checklogin', (req, res) => {
      ...  
      // 執(zhí)行sql查詢
      const sqlStr = `select * from users where username='${username}' and password='${password}'`
      connection.query(sqlStr, (err, data) => {
        if(err) {
          console.log(err)
        }else {
          res.send(data)
        }
      })
    })
    
  4. 重啟服務(wù)器,會(huì)顯示數(shù)據(jù)庫(kù)連接成功。提交表單,在 Response 中可以看到發(fā)送回來的 data:

    數(shù)據(jù)庫(kù)連接成功
    得到數(shù)據(jù)
  1. 渲染頁(yè)面,在 login.vue 中

    .then(response => {
      if(response.data.length) {
        console.log('接收后端響應(yīng)的數(shù)據(jù)', response.data[0].username)
        _this.$message({
          message: '恭喜你,登錄成功!',
          type: 'success'
        })
      }else {
        _this.$message.error('請(qǐng)檢查用戶名或密碼')
      }
    })
    

3.保存登錄數(shù)據(jù)

3.1.vue異步加載組件

繼續(xù)在 login.vue 中

.then(response => {
  if(...){
    ...
    // 跳轉(zhuǎn)到首頁(yè)
    _this.$router.push('/index')
  }
  ...
})

那么我們需要在 vuexms\src\components 增加一個(gè)頁(yè)面組件 index.vue

<template>
  <h1>index</h1>
</template>
...

在路由中配置,并將引入的方式改為異步加載

// 引入組件
// import login from '@/components/login'
// import index from '@/components/index'

// 異步加載
const login = () => import('@/components/login')
const index = () => import('@/components/index')

export default new Router({
  routes: [
    ...
    {
      path: '/',
      name: 'index',
      component: index
    }
  ]
})

3.2存入登錄用戶數(shù)據(jù)

  1. 安裝 vuex 包,在項(xiàng)目控制臺(tái):

    npm i vuex -S
    
  2. 在 src 目錄下新建 vuex 文件夾然后新建 store.js 文件:

    // 引入 vuex
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 注冊(cè) vue
    Vue.use(Vuex)
    
    // 狀態(tài)
    const state = {
      userinfo: JSON.parse(localStorage.getItem('userinfo'))
    }
    // mutations 用于操作 state
    const mutations = {
      // 保存用戶數(shù)據(jù)
      SAVE_USERINFO (state, userinfo) {
    
        // 把用戶數(shù)據(jù)放到本地存儲(chǔ)實(shí)現(xiàn)持久化
        localStorage.setItem('userinfo', JSON.stringify(userinfo))
    
        state.userinfo = userinfo
        console.log('賦值后的用戶信息:' , state.userinfo)
      }
    }
    
    // 創(chuàng)建 store 倉(cāng)庫(kù)暴露出去
    export default new Vuex.Store({
      state,
      mutations
    })
    
  3. 在 src\main.js 中

    ...
    import store from './vuex/store'
    ...
    new Vue({
      ...
      store,
    })
    
  4. login.vue

    .then(response => {
      if(...){
        ...
        // 把當(dāng)前用戶數(shù)據(jù)存入 state
        _this.$store.commit('SAVE_USERINFO', response.data[0])
        ...
        _this.$router.push('/')
      }
      ...
    })
    
  5. index.vue 主頁(yè)調(diào)用

    <template>
      ...
        <p>用戶信息:{{ $store.state.userinfo }}</p>
      ...
    </template>
    
得到數(shù)據(jù)

4.主頁(yè)

4.1.樣式

在 element 中選個(gè)喜歡的 container 組件樣式粘貼到 components\index.vue 組件中,進(jìn)行修改調(diào)整

主頁(yè)樣式

4.2.路由跳轉(zhuǎn)

簡(jiǎn)單添加幾個(gè)其余的頁(yè)面組件,例如:userlist.vue, useradd.vue, passwordedit.vue。重要的是實(shí)現(xiàn)路由跳轉(zhuǎn),而在 element-ui 中有 router 屬性可以幫助我們節(jié)省步驟。

首先,確定需要進(jìn)行跳轉(zhuǎn)的樣式模塊,也就是頁(yè)面左側(cè)的導(dǎo)航欄,在元素中加入 router 屬性:

<el-menu :default-openeds="['1']" router>

然后試著點(diǎn)擊導(dǎo)航欄目錄,網(wǎng)頁(yè)地址會(huì)加上 el-menu-item 元素的 index 屬性的值。

然后,在 router\index.js 中:

// 引入
const home = () => import('@/components/home')
const userlist = () => import('@/components/userlist')
const useradd = () => import('@/components/useradd')
const passwordedit = () => import('@/components/passwordedit')
...
routes: [
  ...
  {
    path: '/',
    redirect: '/home',
    name: 'index',
    component: index,
    children: [
      {
        path: '/home',
        name: 'home',
        component: home
      },        
      {
        path: '/userlist',
        name: 'userlist',
        component: userlist
      },
      {
        path: '/useradd',
        name: 'useradd',
        component: useradd
      },
      {
        path: '/passwordedit',
        name: 'passwordedit',
        component: passwordedit
      },
]

4.3.獲取state數(shù)據(jù)

想要在默認(rèn)頁(yè)面得到展示當(dāng)前用戶的一些數(shù)據(jù),就要從 state 中獲取,vuex 提供了一種更加簡(jiǎn)單的方式來幫助我們獲取到數(shù)據(jù),在 components\home.vue 中:

// 引入 mapState
import {mapState} from 'vuex'

export default {
  computed: {
    // 輔助函數(shù) 獲取 state 數(shù)據(jù)
    ...mapState({
      // userinfo: this.$store.state.userinfo
      userinfo: state => state.userinfo
    })
  }
}

5.用戶列表頁(yè)

5.1.觸發(fā)actions異步獲取數(shù)據(jù)

在 vuexms\src\vuex\store.js 中發(fā)起請(qǐng)求:

// 引入 axios
import axios from 'axios'
...
const state = {
  ...
  userList: []
}
const mutations = {
  ...
  // 獲取全局的用戶數(shù)據(jù)
  GET_USERLIST (state, userList) {
    state.userList = userList
  }
}
// 定義 actions 異步的主要是 commit mutations,由 mutations 來改變狀態(tài)
const actions = {
  GET_USERLIST({ commit }) {
    // 使用 Promise,其他頁(yè)面可以通過 .then 的方式來保證頁(yè)面渲染前得到數(shù)據(jù)
    return new Promise((resolve, reject) => { 
      axios.get('/api/getuserlist').then(response => {
        // console.log('獲取用戶數(shù)據(jù)列表', response.data)
        commit('GET_USERLIST', response.data)
        resolve()
      })
    })
  }
}
export default new Vuex.Store({
  state,
  mutations,
  actions
})

在服務(wù)端 server\routes\index.js 響應(yīng):

// 接收獲取用戶列表的請(qǐng)求
router.get('/getuserlist', (req, res) => {
  // 查詢數(shù)據(jù)庫(kù) 把當(dāng)前素有用戶數(shù)據(jù)返回給前端
  const sqlStr = 'select * from users'
  connection.query(sqlStr, (err, data) => {
    if(err) {
      throw err
    }else {
      res.send(data)
    }
  })
}) 

檢查是否傳回?cái)?shù)據(jù),在 vuexms\src\components\userlist.vue 中:

created() {
    this.$store.dispatch('GET_USERLIST').then(() => {
    console.log(this.$store.state.userList)
  })
}
拿到數(shù)據(jù)

5.2.渲染頁(yè)面

繼續(xù)操作 userlist.vue 文件:

// 引入輔助函數(shù)
import {mapState, mapActions} from 'vuex'

// 刪除之前的假數(shù)據(jù)
data() {
  return {
    tableData: []
  }
},
created() {
  // 以下方式冗長(zhǎng)不擅于管理
  // this.$store.dispatch('GET_USERLIST').then(() => {
  //   // console.log(this.$store.state.userList)
  //   // 把全局的 userlist 賦值給 tableData
  //   // this.tableData = this.$store.state.userList
  // })
  this.getUserList().then(() => {
    this.tableData = this.userList
  })
},
methods: {
  ...mapActions({
    getUserList: 'GET_USERLIST'
  }),
},
computed: {
  ...mapState({
    userList: state => state.userList
  })
}
渲染用戶列表

5.3.過濾

為了使用 getters 屬性,在復(fù)制本頁(yè)面用戶列表添加到下方,并改為目標(biāo)用戶表,我們做過濾出年齡大于20歲的用戶列表這個(gè)操作:

data() {
  return {
    tableData: [],
    newtableData: []
  };
},
created() {
  this.getUserList().then(() => {
    ...
    this.newtableData = this.userList.filter(v => v.age > 20)
  });
}

把需要獲取的數(shù)據(jù)定義成全局的,但是效果不變,在 vuex\store.js 中:

// 定義全局共享屬性 getter
const getters = {
  vipUsers: state => state.userList.filter(v => v.age > 20)
}

export default new Vuex.Store({
  ...
  getters
})

回到 userlist.vue 文件:

created() {
  this.getUserList().then(() => {
    ...
    // this.newtableData = this.userList.filter(v => v.age > 20)
    this.newtableData = this.$store.getters.vipUsers
  });
}

使用 mapGetters 輔助函數(shù)使編寫更簡(jiǎn)潔:

import { mapState, mapActions, mapGetters} from "vuex";
...
created() {
  this.getUserList().then(() => {
    ...
    this.newtableData = this.vipUsers
  });
}
...
computed: {
  ...mapGetters(['vipUsers']),
  ...
}
目標(biāo)用戶

到此,對(duì) vuex 的重要屬性就基本都使用了,也搭好了一個(gè)簡(jiǎn)單的管理系統(tǒng)模板。

我有意將它具化成較詳盡的資產(chǎn)管理系統(tǒng),等完成以后發(fā)布出來。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • vue-cli搭建項(xiàng)目 確保安裝了node與npm 再目標(biāo)文件夾下打開終端 執(zhí)行cnpm i vue-cli -g...
    Akiko_秋子閱讀 3,354評(píng)論 1 22
  • 封面? / 花瓣網(wǎng)@猴哥MONKI 1 盛夏遠(yuǎn)去,秋天不知不覺就來了。 都說秋冬是戀愛的季節(jié),很奇怪,西安的秋天今...
    入世新鮮人閱讀 326評(píng)論 0 0
  • 寫一個(gè)人物可以用以下幾種方法進(jìn)行選材和構(gòu)思。 一、一事反映一品質(zhì)。例如《背影》需要注意:選材,要典型,內(nèi)容要具體,...
    荷塘戀雨閱讀 288評(píng)論 0 2
  • 盤古破開蛋殼,分開天地之后,過了大約九萬年。天地萬物慢慢熟悉了彼此的存在,進(jìn)入了一個(gè)和諧的狀態(tài)。 這一天,大地之上...
    尋找大蝴蝶閱讀 629評(píng)論 0 1

友情鏈接更多精彩內(nèi)容