溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí)

發(fā)布時(shí)間:2020-09-22 19:52:14 來源:腳本之家 閱讀:170 作者:mufengsm 欄目:web開發(fā)

一、日歷組件

new Date()的月份是從0開始的。

下面表達(dá)式是:2018年6月1日
new Date(2018, 5, 1);

下面表達(dá)式是:2018年5月1日
new Date(2018, 4, 1);
或
new Date(2018, 5-1, 1);

下面表達(dá)式是:2018年5月31日(得到上個(gè)月的最后一天)
new Date(2018, 5 , 0);
日的參數(shù)可以是0,也可以是負(fù)數(shù),表示上個(gè)月底的那一天。

下面表達(dá)式是:2018年7月01日
new Date(2018, 5, 31);

lApp.vue父組件:

<template>
 <div>
 <MonthView :year="year" :month="month"></MonthView>
 </div>
</template>
<script>
 import MonthView from "./components/MonthView.vue";
 export default {
 data(){
 return {
 year : 2018 ,
 month : 8 ,
 }
 },
 components : {
 MonthView
 },
 methods : {
 }
 }
</script>

lMonthView.vue子組件

<template>
<div>
 月視圖{{year}} {{month}}
 {{arr}}
 </div>
</template>
<script>
 export default {
 props : ["year" , "month"],
 computed : {
 arr(){
 //計(jì)算日歷的數(shù)組:三要素
 //本月1號(hào)星期幾
 var this1DayWeek = new Date(this.year, this.month - 1, 1).getDay();
 // 本月有幾天
 var thisMonthDay = new Date(this.year, this.month, 0).getDate();
 // 上月有多少天
 var prevMonthDay = new Date(this.year, this.month - 1, 0).getDate();

 console.log(benyue1haoxingqiji)
 console.log(benyueyoujitian)
 console.log(shangyueduoshaotian)
 }
 }
 }
</script>

l顯示在頁面:

<template>
 <div>
 <table>
 <tr v-for="i in 6">
 <td v-for="j in arr.slice((i-1) * 7, i * 7)">
  {{j}}
 </td>
 </tr>
 </table>
 </div>
</template>
<script>
 export default {
 props:["year","month"],
 computed : {
 arr(){
 var _arr = []; //存儲(chǔ)42天的數(shù)組

 // 計(jì)算日歷的數(shù)組:三要素
 //本月1號(hào)星期幾,根據(jù)星期幾得到上個(gè)月剩余天數(shù)
 var this1DayWeek = new Date(this.year, this.month-1, 1).getDay();
 //上個(gè)月有多少天
 var prevMonthDay = new Date(this.year, this.month-1, 0).getDate();
 //本月有幾天
 var thisMonthDay = new Date(this.year, this.month, 0).getDate();

 //用本月1號(hào)星期幾,推斷出上月的剩余天數(shù)
 for(var i = 0; i < this1DayWeek;i++){
  _arr.unshift(prevMonthDay - i)
 }
 
 //循環(huán)本月天數(shù)(累加),從數(shù)組末尾插入
 for(var i = 1; i <= thisMonthDay;i++){
  _arr.push(i)
 }

 //補(bǔ)充下月的天數(shù)(滿42天為止)
 var i = 1;
 while(_arr.length != 42){
  _arr.push(i++);
 }
 
 return _arr;
 }
 }
 }
</script>

l顯示農(nóng)歷,安裝插件:

npm install solarlunar --save

<template>
 <div>
 <h2>月視圖 {{year}}年{{month}}月</h2>
 <table>
 <tr>
 <th>日</th>
 <th>一</th>
 <th>二</th>
 <th>三</th>
 <th>四</th>
 <th>五</th>
 <th>六</th>
 </tr>
 <tr v-for="i in 6">
 <td v-for="j in arr.slice((i-1) * 7, i * 7)">
  <p class="p1">{{j.d}}</p>
  <p class="p2">{{j.n}}</p>
 </td>
 </tr>
 </table>
 </div>
</template>
<script>
 import solarLunar from 'solarLunar';
 export default {
 props:["year","month"],
 computed : {
 arr(){
 var _arr = []; //存儲(chǔ)42天的數(shù)組

 // 計(jì)算日歷的數(shù)組:三要素
 //本月1號(hào)星期幾,根據(jù)星期幾得到上個(gè)月剩余天數(shù)
 var this1DayWeek = new Date(this.year, this.month-1, 1).getDay();
 //上個(gè)月有多少天
 var prevMonthDay = new Date(this.year, this.month-1, 0).getDate();
 //本月有幾天
 var thisMonthDay = new Date(this.year, this.month, 0).getDate();

 //用本月1號(hào)星期幾,推斷出上月的剩余天數(shù)
 for(var i = 0; i < this1DayWeek;i++){
  _arr.unshift({
  d: prevMonthDay - i,
  n: solarLunar.solar2lunar(this.year, this.month-1, prevMonthDay - i).dayCn
  })
 }
 
 //循環(huán)本月天數(shù),累加,從數(shù)組末尾插入
 for(var i = 1; i <= thisMonthDay;i++){
  _arr.push({
  d: i,
  n: solarLunar.solar2lunar(this.year, this.month, i).dayCn
  })
 }

 //補(bǔ)充下個(gè)月的天數(shù)(滿42天為止)
 var i = 1;
 while(_arr.length != 42){
  _arr.push({
  d : i,
  n : solarLunar.solar2lunar(this.year, this.month+1, i).dayCn
  });
  i++;
 }
 console.log(_arr)
 return _arr;
 }
 }
 }
</script>

下面做“換月?lián)Q年”業(yè)務(wù):

App.vue父組件

<template>
 <div>
 <MonthChooser 
 :year="year" 
 :month="month" 
 :setYear="setYear" 
 :setMonth="setMonth"
 >
 </MonthChooser>
 <MonthView :year="year" :month="month"></MonthView>
 </div>
</template>
<script>
 import MonthView from "./components/MonthView.vue";
 import MonthChooser from "./components/MonthChooser.vue";
 export default {
 data(){
 return{
 year :2018,
 month:8,
 }
 },
 components :{
 MonthView,
 MonthChooser
 },
 methods : {
 setYear(year){
 this.year = year; //設(shè)置年
 },
 setMonth(month){
 this.month = month; //設(shè)置月
 }
 }
 }
</script>

MonthChooser.vue切換年月組件

<template>
 <div>
 <h2>
 <button @click="goPrev()">-</button>
 <a href="###">{{year}}</a> 年{{month}}月
 <button @click="goNext()">+</button>
 </h2>
 </div>
</template>
<script>
 export default {
 props:["year","month","setYear","setMonth"],
 methods :{
 goNext(){
  if(this.month < 12){
  // 如果月份小于12,可以加月
  this.setMonth(this.month + 1)
  }else{
  // 否則就加年,并且重設(shè)下年為1月
  this.setMonth(1)
  this.setYear(this.year + 1)
  }
 },
 goPrev(){
  if(this.month > 1){
  // 如果月份大于1月,可以減月
  this.setMonth(this.month - 1)
  }else{
  // 否則就減年,并且重設(shè)上年為12月
  this.setMonth(12); //重設(shè)為12月
  this.setYear(this.year - 1); //減年
  }
 }
 }
 }
</script>

切換年代視圖組件:

lApp.vue父組件

<template>
 <div>
 <MonthChooser
 :year="year"
 :month="month"
 :setYear="setYear"
 :setMonth="setMonth"
 ></MonthChooser>
 <MonthView :year="year" :month="month"></MonthView>
 <DecadeView :year="year" :setYear="setYear"></DecadeView>
 </div>
</template>
<script>
 import MonthView from "./components/MonthView.vue";
 import MonthChooser from "./components/MonthChooser.vue";
 import DecadeView from "./components/DecadeView.vue";
 export default {
 data(){
 return {
 ...
 }
 },
 components : {
 MonthView,
 MonthChooser,
 DecadeView
 },
 methods : {
 ...
 }
 }
</script>

lDecadeView.vue子組件

<template>
 <div>
 <table>
 <tr v-for="i in 10">
 <!-- <td v-for="j in arr.slice((i-1) * 3, i * 3)"> -->
 <td v-for="j in 3" :class="{'cur':year == showYear(i, j)}" 
@click="setYear(showYear(i, j))"
>
  {{showYear(i, j)}}
 </td>
 </tr>
 </table>
 </div>
</template>
<script>
 export default {
 props : ["year"],
 computed : {
 arr(){
 var _arr = [];
 //計(jì)算年份的頭
 var tou = this.year - this.year % 10 - 10;
 //從得到的年份的頭開始循環(huán) + 30
 for(var i = tou ; i < tou + 30;i++){
  _arr.push(i); 
 }
 return _arr;
 }
 },
 methods : {
 showYear(i , j){
 return this.arr[(j - 1) * 10 + (i - 1)]
 }
 }
 }
</script>
<style>
 .cur{color:red;font-weight:bold;}
</style>

【以下開始完善整個(gè)項(xiàng)目】:

切換視圖:App.vue父組件

<template>
 <div>
 <MonthChooser
 :year="year"
 :month="month"
 :setYear="setYear"
 :setMonth="setMonth"
 :setView="setView"
 v-if="view == 'month'"
 ></MonthChooser>
 <MonthView :year="year" :month="month" v-if="view == 'month'"></MonthView>

 <DecadeChooser
 :year="year"
 :month="month"
 :setYear="setYear"
 :setMonth="setMonth"
 :setView="setView"
 v-if="view=='decade'"
 ></DecadeChooser>
 <DecadeView
 :year="year"
 :setYear="setYear"
 v-if="view == 'decade'"
 :setView="setView"
 ></DecadeView>
 </div>
</template>
<script>
 import MonthView from "./components/MonthView.vue";
 import MonthChooser from "./components/MonthChooser.vue";
 import DecadeChooser from "./components/DecadeChooser.vue";
 import DecadeView from "./components/DecadeView.vue";
 export default {
 data(){
 return {
 year : 2018 ,
 month : 5 ,
 view : "month"
 }
 },
 components : {
 MonthView,
 MonthChooser,
 DecadeView,
 DecadeChooser
 },
 methods : {
 ...
 setView(view){
 this.view = view; //設(shè)置視圖切換
 }
 }
 }
</script>

DecadeChooser.vue年視圖按鈕組件:

<template>
 <div>
 <h2>
 <button @click="goPrev()">-</button>
 {{year}}年<a href="javascript:;" @click="setView('month')">{{month}}月</a>
 <button @click="goNext()">+</button>
 </h2>
 </div>
</template>
<script>
 export default{
 props : ["year", "month" , "setYear","setView"],
 methods : {
 goNext(){
 this.setYear(this.year + 1)
 },
 goPrev(){
 if(this.year <= 1970) return;
 this.setYear(this.year - 1)
 }
 }
 }
</script>

MonthChooser.vue月視圖按鈕組件:

<template>
 <div>
 <h2>
 <button @click="goPrev()">-</button>
 <a href="javascript:;" @click="setView('decade')">{{year}}</a>年{{month}}月
 <button @click="goNext()">+</button>
 </h2>
 </div>
</template>
<script>
 export default{
 props : ["year", "month" , "setYear", "setMonth","setView"],
 methods : {
 goNext(){
 ...
 },
 goPrev(){
 ...
 }
 }
 }
</script>

DecadeView.vue年份視圖組件:

<template>
 <div>
 <table>
 <tr v-for="i in 10">
 <td
  v-for="j in 3"
  :class="{'cur' : year == showYear(i , j)}"
  @click="tdClick(i,j)"
 >
  {{showYear(i , j)}}
 </td>
 </tr>
 </table>
 </div>
</template>
<script>
 export default {
 props : ["year","setYear","setView"],
 computed : {
 arr(){
 ...
 }
 },
 methods : {
 showYear(i , j){
 return this.arr[(j - 1) * 10 + (i - 1)]
 },
 tdClick(i , j){
 this.setYear(this.showYear(i , j)); //切換年份
 this.setView("month"); //切換年份后,回到月視圖
 }
 }
 }
</script>

MonthView.vue月視圖早已完善。

二、UI組件庫

餓了么UI:http://element-cn.eleme.io/

iviewUI :https://www.iviewui.com/

2.1餓了么UI

以餓了么UI為例

安裝依賴:

npm install --save element-ui

在main.js中配置eleUI組件:

在引入 Element 時(shí),可以傳入一個(gè)全局配置對象。該對象目前僅支持 size 字段,用于改變組件的默認(rèn)尺寸。按照引入 Element 的方式,具體操作如下:

import Vue from "vue";
import App from "./App.vue";
import ElementUI from 'element-ui';
//import 'element-ui/lib/theme-chalk/index.css'; //樣式在index.html頁面引入
// Vue.use(ElementUI);
Vue.use(ElementUI, { size: 'small' });

new Vue({
 el : "#app" ,
 render: (h) => h(App)
});

然后就可以在.vue組件中直接使用了。

2.2 iviewui

npm install iview --save

三、傳統(tǒng)數(shù)據(jù)管理的問題

以下是一個(gè)表示“單向數(shù)據(jù)流”理念的極簡示意:

Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí)

當(dāng)我們的應(yīng)用遇到多個(gè)組件共享狀態(tài)時(shí),單向數(shù)據(jù)流的簡潔性很容易被破壞:

多個(gè)視圖依賴于同一狀態(tài)。

來自不同視圖的行為需要變更同一狀態(tài)。

對于問題1:傳參的方法對于多層嵌套的組件將會(huì)非常繁瑣,并且對于兄弟組件間的狀態(tài)傳遞無能為力。

對于問題2:我們經(jīng)常會(huì)采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通常會(huì)導(dǎo)致無法維護(hù)的代碼。

因此,我們?yōu)槭裁床话呀M件的共享狀態(tài)抽取出來,以一個(gè)全局單例模式管理呢?在這種模式下,我們的組件樹構(gòu)成了一個(gè)巨大的“視圖”,不管在樹的哪個(gè)位置,任何組件都能獲取狀態(tài)或者觸發(fā)行為!

另外,通過定義和隔離狀態(tài)管理中的各種概念并強(qiáng)制遵守一定的規(guī)則,我們的代碼將會(huì)變得更結(jié)構(gòu)化且易維護(hù)。

這就是 Vuex 背后的基本思想,借鑒了 Flux、Redux、和 The Elm Architecture。與其他模式不同的是,Vuex 是專門為 Vue.js 設(shè)計(jì)的狀態(tài)管理庫,以利用 Vue.js 的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來進(jìn)行高效的狀態(tài)更新。

之前我們做的日歷組件將數(shù)據(jù)放到了App.vue最大父組件上,并且還有:year、:month、:setYear、:setMonth等一系列的參數(shù)傳遞操作。

但是vuex就是將數(shù)據(jù)放到了全局store中。

不用vuex也能做項(xiàng)目,只不過數(shù)據(jù)管理起來很不方便。

四、Vuex4.1 Vuex配置

官網(wǎng):https://vuex.vuejs.org/zh-cn/

安裝vuex:

npm install --save vuex

什么是vuex?

Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。

簡單說:vuex就是一個(gè)狀態(tài)管理容器,說白了就是將數(shù)據(jù)單獨(dú)存放出去。

4.2 state(全局倉庫)

什么是“狀態(tài)管理模式”?

每個(gè)Vuex應(yīng)用的核心就是store(倉庫)。store就是一個(gè)容器,它包含著你項(xiàng)目中大部分的狀態(tài) (state)。

Vuex 和單純的全局對象有以下兩點(diǎn)不同:

Vuex的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新變化。

你不能直接改變store中的狀態(tài)。改變store中的狀態(tài)的唯一途徑就是通過commit提交mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。

在main.js創(chuàng)建一個(gè)全局倉庫(store),讓我們從一個(gè)簡單的Vue計(jì)數(shù)器開始:

import Vue from 'vue';
import Vuex from 'vuex'; //引入Vuex包
import App from './App.vue';
Vue.use(Vuex); //將vuex安裝到vue中

//創(chuàng)建一個(gè)倉庫,并且存放一些全局?jǐn)?shù)據(jù)(存放四大天王選項(xiàng))
const store = new Vuex.Store({
 state : {
 a : 100
 }
})

new Vue({
 el : "#app",
 store, //將store注入到全局中
 render : (h)=> h(App)
})

Vuex通過store選項(xiàng),提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個(gè)子組件中(需要調(diào)用Vue.use(Vuex))

通過在根實(shí)例中注冊store選項(xiàng),該store實(shí)例會(huì)注入到根組件下的所有子組件中,并且組件能通過this.$store訪問。

在App.vue中的生命周期中輸出this,能看到vue實(shí)例化對象的全局有$store這個(gè)對象

<template>
 <div>
 <h2>全局倉庫state對象的a值:{{$store.state.a}}</h2>
 </div>
</template>
<script>
 export default {
 created(){
  console.log(this)
  console.log(this.$store.state.a)
 }
 }
</script>

Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí)

之前做的日歷組件將數(shù)據(jù)放到了App.vue最大父組件上,并且還有:year、:month、:setYear、:setMonth等一系列的參數(shù)傳遞操作。

但是Vuex就是將數(shù)據(jù)放到了全局store中,注意:

不管項(xiàng)目有多大,store只有一個(gè)

只要配置正確,組件內(nèi)部可以使用$store即可訪問store的全局?jǐn)?shù)據(jù)

改變 store 中的狀態(tài)(數(shù)據(jù))的唯一途徑就是通過commit()函數(shù)提交 mutation。

以下的描述來自于官方:https://vuex.vuejs.org/zh/guide/

再次強(qiáng)調(diào),我們通過提交 mutation 的方式,而非直接改變 store.state.a,是因?yàn)槲覀兿胍鞔_地追蹤到狀態(tài)的變化。這個(gè)簡單的約定能夠讓你的意圖更加明顯,這樣你在閱讀代碼的時(shí)候能更容易地解讀應(yīng)用內(nèi)部的狀態(tài)改變。此外,這樣也讓我們有機(jī)會(huì)去實(shí)現(xiàn)一些能記錄每次狀態(tài)改變,保存狀態(tài)快照的調(diào)試工具。有了它,我們甚至可以實(shí)現(xiàn)如時(shí)間穿梭般的調(diào)試體驗(yàn)。

由于 store 中的狀態(tài)是響應(yīng)式的,在組件中調(diào)用 store 中的狀態(tài)簡單到僅需要在計(jì)算屬性中返回即可。觸發(fā)變化也僅僅是在組件的 methods 中提交 mutation。

4.3 mutations

更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex中的mutation非常類似于事件:每個(gè) mutation都有一個(gè)字符串的 事件類型(type)和一個(gè)回調(diào)函數(shù) (handler)。這個(gè)回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會(huì)接受 state 作為第一個(gè)參數(shù):

你不能直接調(diào)用一個(gè)mutation handler。這個(gè)選項(xiàng)更像是事件注冊:當(dāng)觸發(fā)一個(gè)type類型為JIA的 mutation時(shí),調(diào)用此函數(shù)。要喚醒一個(gè)mutation函數(shù),你需要以相應(yīng)的type調(diào)用store.commit()方法:

main.js

import Vue from 'vue';
import Vuex from 'vuex'; //引入Vuex包
import App from './App.vue';
Vue.use(Vuex); //將vuex安裝到vue中

//創(chuàng)建一個(gè)倉庫,并且存放一些全局?jǐn)?shù)據(jù)(存放四大選項(xiàng))
const store = new Vuex.Store({
 state : {
 a : 100
 },
 mutations : {
 // 這里的函數(shù)只能通過commit()觸發(fā),其他操作是無法影響的
 JIA(state){
  state.a++
 },
 MINUS(state){
  state.a--
 }
 }
})

App.vue

<template>
 <div>
 <h2>全局倉庫state對象的a:{{$store.state.a}}</h2>
 <button @click="add()">+</button>
 <button @click="minus()">-</button>
 </div>
</template>
<script>
export default {
 methods:{
 add(){
  // this.$store.state.a++ //不允許直接改全局的state數(shù)據(jù)
  this.$store.commit("JIA");
 },
 minus(){
  this.$store.commit("MINUS");
 }
 }
};
</script>

>[/code]

Vuex自帶一個(gè)日志插件(vue-logger)用于調(diào)試:

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
 plugins: [createLogger()]
})

總結(jié):

只有mutations中可以改變state,其他任何方式都不能改state的值

組件想要改變store中的state,只能通過commit()發(fā)出一條命令。

提交載荷(Payload)

你可以向 store.commit() 傳入額外的參數(shù),即 mutation 的 載荷(payload),在大多數(shù)情況下,載荷應(yīng)該是一個(gè)對象,這樣可以包含多個(gè)字段并且記錄的 mutation 會(huì)更易讀:

main.js

import Vue from 'vue';
import Vuex from 'vuex'; //引入Vuex包
import App from './App.vue';
import createLogger from 'vuex/dist/logger';

Vue.use(Vuex); //將vuex安裝到vue中

//創(chuàng)建一個(gè)倉庫,并且存放一些全局?jǐn)?shù)據(jù)(存放四大選項(xiàng))
const store = new Vuex.Store({
 state : {
 a : 100
 },
 mutations : {
 // 這里的函數(shù)只能通過commit()觸發(fā),其他操作是無法影響的
 JIA(state,payload){
  state.a += payload.n
 },
 MINUS(state, payload){
  state.a -= payload.n
 }
 },
 plugins: [createLogger()]
})

App.vue

<template>
 <div>
 <h2>全局倉庫state對象的a:{{$store.state.a}}</h2>
 <button @click="add()">+</button>
 <button @click="minus()">-</button>
 <button @click="add(2)">+</button>
 <input type="text" ref="txt">
 <button @click="addUser()">加用戶輸入的數(shù)</button>
 </div>
</template>
<script>
export default {
 methods:{
 add(n=1){
  // this.$store.state.a++ //不允許直接改全局的state數(shù)據(jù)
  // this.$store.commit("JIA", 8);
  this.$store.commit("JIA", {n});
 },
 minus(){
  this.$store.commit("MINUS", {n : 10});
 },
 addUser(){
  this.$store.commit("JIA", {n : Number(this.$refs.txt.value)});
 }
 }
};
</script>

記住一條重要的原則:mutations必須是同步函數(shù)

4.4 actions

上面說過mutation 中不能寫異步語句,為了處理異步操作,我們來看一看action

action 類似于 mutation,不同在于:

action 提交的是 mutation,而不是直接變更狀態(tài)。

action 可以包含任意異步操作。

action 要通過 store.dispatch() 方法觸發(fā)

注意:涉及到異步Ajax請求數(shù)據(jù),案例必須運(yùn)行在服務(wù)器端(127.0.0.1)

新建一個(gè)data文件夾,創(chuàng)建txt文件。使用ajax 異步讀取文本文件中數(shù)據(jù):

App.vue父組件:

<script>
 export default {
 methods:{
  add(){
  this.$store.dispatch("JIA");
  }
 }
 }
</script>

main.js

const store = new Vuex.Store({
 state : {
 a : 100
 },
 mutations : {
 JIA(state,payload){
  console.log("只有commit命令能觸發(fā)我")
  state.a += payload.n
 }
 },
 actions : {
 async JIA({commit}){
  // console.log("只有dispatch命令能觸發(fā)我,這里可以寫異步語句")
  var data = await fetch('../data/1.txt').then(data=>data.json())
  //action提交的是mutation,而不是直接更改狀態(tài),
  //請求成功返回的數(shù)據(jù)需要通過commit命令mutations去修改state中的數(shù)據(jù)
       // context.commit("JIA", {n: data})
  // this.commit("JIA", {n: data})
  commit("JIA", {n:data})
 }
 },
 plugins: [createLogger()]
})

actions中的函數(shù),天生自帶默認(rèn)參數(shù)

Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí)

一些概念:

action 函數(shù)接受一個(gè)與store實(shí)例具有相同方法和屬性context對象,因此你可以調(diào)用 context.commit 提交一個(gè) mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters。當(dāng)我們在之后介紹到 Modules 時(shí),你就知道 context 對象為什么不是 store 實(shí)例本身了。

實(shí)踐中,會(huì)經(jīng)常用到ES2015的 參數(shù)解構(gòu) 來簡化代碼(特別是我們需要調(diào)用commit很多次的時(shí)候):

actions:{
 async JIA({commit}){
 var data = await fetch("../data/1.txt").then(data=>data.json());
 commit("JIA",data)
 }
},

action 通過 store.dispatch() 方法觸發(fā):

methods:{
 add(){
 this.$store.dispatch("JIA")
 }
}

乍一眼看上去感覺多此一舉,我們直接分發(fā) mutation 豈不更方便?實(shí)際上并非如此,還記得 mutation 必須同步執(zhí)行這個(gè)限制么?Action 就不受約束!我們可以在 action 內(nèi)部執(zhí)行異步操作:

actions支持同樣的載荷方式和對象方式進(jìn)行分發(fā):

vuex單向數(shù)據(jù)流動(dòng)的圖示:

Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí)

使用 Vuex 并不意味著你需要將所有的狀態(tài)放入Vuex。雖然將所有的狀態(tài)放到 Vuex 會(huì)使?fàn)顟B(tài)變化更顯式和易調(diào)試,但也會(huì)使代碼變得冗長和不直觀。如果有些狀態(tài)嚴(yán)格屬于單個(gè)組件,最好還是作為組件的局部狀態(tài)。你應(yīng)該根據(jù)你的應(yīng)用開發(fā)需要進(jìn)行權(quán)衡和確定。

4.5 getters

有時(shí)候我們需要從 store 中的 state 中派生出一些狀態(tài),例如對列表進(jìn)行過濾并計(jì)數(shù):

computed: {
 arr() {
 return this.$store.state.todos.filter(todo => todo.done).length
 }
}

在Vuex中,getter類似于組件中的computed,表示state的一些計(jì)算后的值。

如果有多個(gè)組件需要用到此屬性,我們要么復(fù)制這個(gè)函數(shù),或者抽取到一個(gè)共享函數(shù)然后在多處導(dǎo)入它——無論哪種方式都不是很理想。

Vuex 允許我們在 store 中定義“getter”(可以認(rèn)為是 store 的計(jì)算屬性)。就像computed計(jì)算屬性一樣,getter 的返回值會(huì)根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算。

Getter 接受 state 作為其第一個(gè)參數(shù):

main.js

import Vue from 'vue';
import Vuex from 'vuex'; //引入Vuex包
import App from './App.vue';
import createLogger from 'vuex/dist/logger'; //調(diào)試工具

Vue.use(Vuex); //將Vuex安裝到全局

//創(chuàng)建一個(gè)倉庫,并且存放以一些全局?jǐn)?shù)據(jù)(存放四大選項(xiàng))
const store = new Vuex.Store({
 state:{
 a:100,
 students:[
  {name:"小明",sex:"男"},
  {name:"小紅",sex:"女"},
  {name:"小剛",sex:"男"},
  {name:"小花",sex:"女"},
  {name:"小黑",sex:"男"}
 ]
 },
 getters:{
 //得到所有男生
 nan(state){
  return state.students.filter((item)=>{
  return item.sex == '男';
  })
 },
 //得到所有女生
 nv(state){
  return state.students.filter((item)=>{
  return item.sex == '女';
  })
 },
 //得到男生和女生的個(gè)數(shù),getter也可以接受getter作為第二個(gè)參數(shù)
 nanCount(state,getters){
  return getters.nan.length;
 },
 nvCount(state,getters){
  return getters.nv.length;
 }
 },
 plugins: [createLogger()]
})

new Vue({
 el:"#app",
 store, //將store注入到全局
 render:(h)=> h(App)
})

App.vue父組件:

<template>
 <div>
 <h2>{{students}}</h2>
 <h3>男生:{{$store.getters.nanCount}}個(gè)</h3>
 <h3>女生:{{$store.getters.nvCount}}個(gè)</h3>
 <button @click="nan">查看男生</button>
 <button @click="nv">查看女生</button>
 <button @click="all">查看全部</button>
 </div>
</template>
<script>
export default {
 data(){
 return {
  isState:'all'
 }
 },
 computed:{
 students(){
  if(this.isState == 'all'){
  return this.$store.state.students;
  }else if(this.isState == 'nan'){
  return this.$store.getters.nan;
  }else if(this.isState == 'nv'){
  return this.$store.getters.nv
  }
 }
 },
 methods:{
 nan(){
  this.isState = 'nan'
 },
 nv(){
  this.isState = 'nv'
 },
 all(){
  this.isState = 'all'
 }
 }

}
</script>

在介紹state中我們了解到,在Store倉庫里,state就是用來存放數(shù)據(jù),若是對數(shù)據(jù)進(jìn)行處理輸出,比如數(shù)據(jù)要過濾,一般我們可以寫到computed中。但是如果很多組件都使用這個(gè)過濾后的數(shù)據(jù),比如餅狀圖組件和曲線圖組件,我們是否可以把這個(gè)數(shù)據(jù)抽提出來共享?這就是getters存在的意義。官網(wǎng)說的很清楚,getters是store的計(jì)算屬性。

getters 可以對State進(jìn)行計(jì)算操作。雖然在組件內(nèi)也可以做,但是getters可以在多組件之間復(fù)用如果一個(gè)狀態(tài)只在一個(gè)組件內(nèi)使用,是可以不用getters

getters上簡單來說就是存放一些公共函數(shù)供組件調(diào)用。getters 會(huì)暴露為 $store.getters 對象,也就是說可以通過 $store.getters[屬性]來進(jìn)行相應(yīng)的調(diào)用。

4.6vuex的命名空間

目錄結(jié)構(gòu):

│ package.json
│ webpack.config.js
│
└─www
 │ index.html
 │
 └─app
 │ App.vue
 │ main.js
 │
 ├─components
 └─store
  │ index.js
  │
  ├─counter
  │ store.js
  │
  └─taobao
   store.js

./package.json:

{
 "name": "vue_study",
 "version": "1.0.0",
 "description": "",
 "main": "webpack.config.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1",
 "dev": "webpack-dev-server --content-base ./www --port 8080"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "dependencies": {
 "vue": "^2.5.17",
 "vuex": "^3.0.1"
 },
 "devDependencies": {
 "css-loader": "^1.0.1",
 "style-loader": "^0.23.1",
 "vue-loader": "^15.4.2",
 "vue-style-loader": "^4.1.2",
 "vue-template-compiler": "^2.5.17",
 "webpack": "^4.9.1",
 "webpack-cli": "^3.1.2"
 }
}

./webpack.config.js:

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
 //程序的入口文件
 entry: "./www/app/main.js",

 //程序的出口(打包的文件)
 output: {
  //打包文件輸出的路徑
  path: path.resolve(__dirname, "./www/dist"),
  //打包文件的名稱
  filename: 'all.js',
  publicPath: "/public" //這是對webpack-dev-server的配置,配置虛擬路徑
 },
 //監(jiān)聽文件的變化(自動(dòng)打包)
 watch: true,
 mode: "development",
 //配置webpack模塊插件
 module: {
  //關(guān)于模塊的配置規(guī)則
  rules: [{
    // 模塊規(guī)則(配置 loader、解析器等選項(xiàng))
    test: /\.js?$/, //解析的時(shí)候匹配js文件
    //翻譯什么文件夾中的文件
    include: [path.resolve(__dirname, "www/app")],
    //不翻譯什么文件夾中的文件
    exclude: [path.resolve(__dirname, "node_modules")],
    // loader:"babel-loader",
    //配置翻譯語法
    // options:{
    //  presets:["es2015","es2016"]
    // }
   },
   {
    test: /\.vue$/,
    loader: 'vue-loader',
    include: [path.resolve(__dirname, "www/app")],
    exclude: [path.resolve(__dirname, "node_modules")],
    options: {
     loaders: {
      js: 'babel-loader!eslint-loader'
     }
    }
   },
   {
    test: /\.css$/,
    include: [path.resolve(__dirname, "www/app")],
    exclude: [path.resolve(__dirname, "node_modules")],
    use: ['vue-style-loader', 'css-loader'],
   },
   {
    test: /\.styl(us)?$/,
    use: [
    'vue-style-loader',
    'css-loader',
    'stylus-loader'
    ]
   }
  ]
 },
 resolve: {
  alias: {
   'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 時(shí)需用 'vue/dist/vue.common.js'
  }
 },
 //最新版webpack需要引入此插件
 plugins: [
  new VueLoaderPlugin()
 ],
 //webpack設(shè)置代理跨越
 devServer: {
  proxy: {
   '/api': {
    target: 'http://127.0.0.1:3000', //設(shè)置你調(diào)用的接口域名和端口
    //這里理解成/api代理target中的地址,后面組件中調(diào)用接口要使用/api代替
    pathRewrite: { '^/api': '' }
   }
  }
 }
}

./www/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8" />
 <title>Document</title>
</head>
<body>
 <div id="app"></div>
</body>
<script type="text/javascript" src="public/all.js"></script>
</html>

./www/app/App.vue:

<template>
 <div>
  <h2>counter的{{$store.state.counterStore.a}}</h2>
  <h2>taobao的{{$store.state.taobaoStore.a}}</h2>
  <button @click="add">觸發(fā)counter的ADD</button>
 </div>
</template>
<script>
  export default {
  methods:{
   add(){
    //根據(jù)命名空間發(fā)出異步
    this.$store.dispatch("counterStore/ADD")
   }
  }
  }
</script>

./www/app/main.js:[

import Vue from "vue";
import App from "./App.vue";
import store from "./store";

new Vue({
 el: "#app",
 store,//引入store文件夾中的index.js
 render: (h) => h(App)
})

./www/app/store/index.js:

import Vue from "vue";
import Vuex from "vuex";
import counterStore from "./counter/store.js";//引入counter的store
import taobaoStore from "./taobao/store.js";//引入taobao的store
import createLogger from 'vuex/dist/logger';

Vue.use(Vuex);

export default new Vuex.Store({
 modules: {//放入modules
  counterStore,
  taobaoStore
 },
 plugins : [createLogger()]
})

./www/app/store/counter/store.js:

export default {
 namespaced: true, //命名空間
 state : {
  a:100
 },
 mutations : {
  ADD(state,payload){
   state.a++//上面的state
  }
 },
 actions : {
  ADD({commit}){
   commit("ADD")//調(diào)用上面mutations的ADD
  }
 }
}

./www/app/store/taobao/store.js:

export default {
 namespaced: true,//開啟命名空間跟上面一樣的用法
 state : {
  a:200
 },
 mutations : {},
 actions : {}
}

五、配置虛擬服務(wù)器

一般情況下,一個(gè)應(yīng)用的數(shù)據(jù)都需要等待后端接口人員開發(fā)完對應(yīng)的接口才可以獲取到,這樣子的效率有點(diǎn)低。最好是我們可以自己模擬接口數(shù)據(jù),進(jìn)行頁面的數(shù)據(jù)填充,打通所有關(guān)節(jié),之后等接口開發(fā)好了,改下接口地址就好了。

所以,作為前端和客戶端開發(fā)人員,在后端還沒有給出對應(yīng)的api接口時(shí),我們無法做測試。

這時(shí),我們可以使用json-server快速搭建一個(gè)測試的api接口,能在幾十秒之內(nèi)搭建好。

json-server 它能模擬“數(shù)據(jù)庫”,提供了一套簡單的API(RESTFUL)接口。

在開發(fā)過程中,前后端不論是否分離,接口多半是滯后于頁面開發(fā)的。所以建立一個(gè)RESTFUL風(fēng)格的API接口,給前端頁面提供虛擬的數(shù)據(jù),是非常有必要的。

因?yàn)樗銐蚝唵危瑢懮倭繑?shù)據(jù),即可使用。

也因?yàn)樗銐驈?qiáng)大,支持CORS和JSONP跨域請求,支持GET, POST, PUT, PATCH 和 DELETE 方法,更提供了一系列的查詢方法,如limit,order等。下面將詳細(xì)介紹 json-server 的使用。

https://github.com/typicode/json-server

總結(jié)

以上所述是小編給大家介紹的Vue中UI組件庫之Vuex與虛擬服務(wù)器初識(shí) ,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對億速云網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI