您好,登錄后才能下訂單哦!
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: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
以下是一個(gè)表示“單向數(shù)據(jù)流”理念的極簡示意:
當(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ù)管理起來很不方便。
官網(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>
之前做的日歷組件將數(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ù)
一些概念:
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)的圖示:
使用 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)載,煩請注明出處,謝謝!
免責(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)容。