安裝相關依賴:javascript
npm install --save-dev webpack
npm install --save-dev babel-loader babel-core babel-preset-es2015
npm install --save-dev vue-loader
npm install --save-dev css-loader
npm install --save-dev vue-template-compiler
npm install --save-dev stylus stylus-loader
npm install --save vue
npm install --save vuex
【第一步:安裝依賴】php
npm install -g json-server
【第二步:json-server的服務器啓動】css
啓動須要json文件做爲支撐,新建data.json文件作服務數據:html
{
"mapList" : [
{"id":1 ,"title" : "吃飯", "done" : false},
{"id":2 ,"title" : "睡覺", "done" : false},
{"id":3 ,"title" : "作飯", "done" : false},
{"id":4 ,"title" : "掃地", "done" : false}
]
}
啓動命令json-server命令:
json-server 數據文件路徑 -s 靜態化目錄 -p 8080
json-server www/data/data.json -s ./www -p 8080
-s是 --static
-p是 --port
最終沒有使用webpack-dev-server模擬服務器前端
配置webpack.config.js文件:vue
const path = require('path'); const {VueLoaderPlugin} = require('vue-loader'); //最新版webpack須要引入插件 module.exports = { //程序的入口文件 entry: "./www/app/app.js", //程序的出口(打包的文件) output : { //打包文件輸出的路徑 path : path.resolve(__dirname, "www/dist"), //打包文件的名稱 filename : "all.js", // publicPath:"/public" //這是對webpack-dev-server的配置,配置虛擬路徑 }, //讓webpack監聽變化,自動打包 watch : true, mode : "development", //配置webpack的模塊插件 module:{ //關於模塊的配置規則 rules : [ { //模塊規則(配置 loader、解析器等選項) test : /\.js$/, //解析的時候匹配到的都是js文件 include: [ path.resolve(__dirname, "www/app") //翻譯什麼文件夾 ], exclude: [ path.resolve(__dirname, "node_modules") //不翻譯什麼文件夾 ], loader : "babel-loader", options : { presets : ["es2015"] } }, { test: /\.vue$/, include: [ path.resolve(__dirname, "www/app") //翻譯什麼文件夾 ], exclude: [ path.resolve(__dirname, "node_modules") //不翻譯什麼文件夾 ], loader: 'vue-loader', options :{ loaders : { stylus:'vue-style-loader!css-loader!stylus-loader' } } }, { test:/\.css$/, 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 時需用 'vue/dist/vue.common.js' } }, //最新版webpack須要引入插件 plugins : [ new VueLoaderPlugin() ] }
【第三步:訪問接口】java
獲取全部的數據:GETnode
增長數據:POSTjquery
獲得某一條數據:GETwebpack
刪除某一條:DELETE
更新原始數據:PUT (更新條目的全部的屬性)、PATH(更新條目的某一個屬性)
自帶分頁:page(第幾頁)limit(每頁有多少條)
http://localhost:8080/mapList 返回.json文件全部數據(數組)
http://localhost:8080/mapList/1 返回id=1的數據,採用這種路徑風格id必須爲小寫(數組)
http://localhost:8080/mapList/?Name=lst 返回Name=lst的用戶數據(數組)
分頁查詢:參數爲 _start, _end, _limit,並可添加其它參數篩選條件,如: http://localhost:8080/mapList?_start=6&_limit=3 http://localhost:8080/mapList?_start=3&_end=6 排序:參數爲_sort, _order http://localhost:8080/mapList?_sort=id&_order=asc http://localhost:8080/mapList?_sort=user,views&_order=desc,asc 操做符:_gte, _lte, _ne, _like _gte大於,_lte小於, _ne非, _like模糊查詢,q關鍵詞查詢 http://127.0.0.1:8080/mapList/?q=吃
相關步驟:
在created生命週期中發出一個GETALL的異步命令,去actions裏面發異步請求。
App.vue
<script> export default { created(){ this.$store.dispatch("GETALL"); } } </script>
main.js
import Vue from "vue"; import Vuex from "vuex"; import App from "./App.vue"; Vue.use(Vuex); const store = new Vuex.Store({ state : { todos : [] }, mutations: { GETALL(state,payload){ // state.todos.push(payload) state.todos = payload; } }, actions :{ async GETALL({commit}){ //請求數據庫中的數據,而後存儲到state的todos中 var data = await fetch("/maplist").then(data=>data.json()); //發出commit()命令,而且將參數當載荷傳遞過去 commit("GETALL", data); } } }); new Vue({ el : "#app", store, render:(h)=>h(App) })
異步請的數據回調成功後,將數據以載荷的形式發送到mutations,再去修改state 的數據
state全局倉庫有了數據,就能夠在App.vue進行循環渲染。
App.vue
<template> <div> <ul> <li v-for="item in todos"> {{item.title}} </li> </ul> </div> </template> <script> export default { created(){ this.$store.dispatch("GETALL"); }, computed : { todos(){ return this.$store.state.todos } } } </script>
下一步:須要將li標籤拆分紅組件:
App.vue
<template> <div> <ul> <li is="TodoLi" v-for="item in todos" :item="item"></li> </ul> </div> </template> <script> import TodoLi from "./components/TodoLi.vue"; export default { created(){ this.$store.dispatch("GETALL"); }, computed : { todos(){ return this.$store.state.todos } }, components:{ TodoLi } } </script>
TodoLi.vue
<template> <li>{{item.title}}</li> </template> <script> export default { props : ["item"] } </script>
接下來寫增刪改查業務,推薦先寫刪除,由於刪除值須要id
TodoLi.vue
<template> <li> <span>{{item.title}}</span> <button @click="del(item.id)">刪除</button> </li> </template> <script> export default { props : ["item"], methods:{ del(id){ this.$store.dispatch("DEL", {id}) } } } </script>
const store = new Vuex.Store({ state : { todos : [] }, mutations: { GETALL(state,payload){ // state.todos.push(payload) state.todos = payload; }, DEL(state, payload){ // 根據id刪除state的數據 state.todos = state.todos.filter(item=>{ return item.id != payload.id; }) } }, actions :{ async GETALL({commit}){ //請求數據庫中的數據,而後存儲到state的todos中 var data = await fetch("/maplist").then(data=>data.json()); //發出commit()命令,而且將參數當載荷傳遞過去 commit("GETALL", data); }, async DEL({commit},payload){ //向服務器發出刪除請求,刪除data.json中的數據 var data = await fetch("/maplist/" + payload.id, { method:"DELETE", }).then(data => data.json()); commit("DEL", payload); //刪除全局state倉庫的數據 }, } });
App.vue
<template> <div> <div> <input type="text" v-model.trim="txt"> <button @click="add">新增</button> </div> <ul> <li is="TodoLi" v-for="item in todos" :item="item"></li> </ul> </div> </template> <script> import TodoLi from "./components/TodoLi.vue"; export default { data(){ return { txt : '' } }, methods :{ add(){ if(this.txt == '') return; //發出新增的異步請求 this.$store.dispatch(ADD, {id: new Date() - 0, title:this.txt, done:false}) this.txt = "" } }, components:{ TodoLi } } </script>
main.js
actions : { //新增數據 async ADD({ commit }, payload) { //向data.json文件中插入數據 var data = await fetch("/maplist/", { method: "POST", headers:{'Content-type' : 'application/json'}, body: JSON.stringify(payload) }).then(data => data.json()); commit("ADD", data); //新增數據到state,影響視圖更新 } }, mutations : { ADD(state, payload) { state.todos.push(payload); } }
TodoLi.vue
<template> <li> <span v-if="!isShow" @dblclick="showInput">{{item.title}}</span> <input type="text" v-if="isShow" v-model="item.title" @blur="hideInput(item)" v-focus> <button @click="del(item.id)">刪除</button> </li> </template> <script> export default { props : ["item"], data(){ return{ isShow:false } }, methods:{ del(id){ this.$store.dispatch("DEL", {id}) }, showInput(){ //雙擊顯示input this.isShow = !this.isShow; }, hideInput(item){ console.log(item) //失去焦點隱藏input,而且發送CAHNGETITLE命令修改title內容 this.isShow = !this.isShow; this.$store.dispatch("CHANGETITLE",item) } }, directives:{ //自定義組件指令,自動獲取焦點 focus :{ inserted(el){ el.focus(); } } } } </script>
main.js
const store = new Vuex.Store({ state : { todos : [] }, mutations: { CHANGETITLE(state, payload) { // 寫法1 // state.todos.forEach(item=>{ // if (item.id == payload.id){ // item.title = payload.title; // } // }) // 寫法2 state.todos = state.todos.map(item => { if(item.id == payload.id) { return payload } return item; }) } }, actions :{ //修改請求 async CHANGETITLE({commit}, payload) { var data = await fetch("/maplist/" + payload.id, { method: "PATCH", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).then(data => data.json()); commit("CHANGETITLE", data); //雖然實現了修改,可是爲了完整性仍是寫上 }, } });
修改任務事件:當前任務是否作了,須要一個複選框
todoli.vue
<li> <input type="checkbox" v-model="item.done" ref="cbox" @click="changeDone(item)"> <spanv-if="!isShowInput"@dblclick="showInput" :class="{cur:item.done}">{{item.title}}</span> </li> <script> methods:{ changeDone(item){ console.log(this.$refs.cbox.checked); // 這裏使用的是ref鉤子 這樣能獲得 複選框的狀態 // 提交的時候 只須要提交 id 複選框的狀態就好了 this.$store.dispatch("CHANGEDONE",{ id : item.id, done : this.$refs.cbox.checked }) } } </script> <style> .cur{text-decoration: line-through;} </style>
app.js修改done和修改title的方式方法都同樣,只要改方法名便可。
const store = new Vuex.Store({ mutations:{ CHANGEDONE(state, payload){ state.todos = state.todos.map(item => { if(item.id == payload.id){ return payload } return item }) } }, actions:{ async CHANGEDONE({commit},payload){ var data = await fetch("/mapList/" + payload.id,{ "method" : 'PATCH', "headers":{ 'Content-Type':"application/json" }, body:JSON.stringify({done:payload.done}) }).then(res => res.json()); commit("CHANGEDONE",data) }, } });
篩選按鈕:計算已作未作事項
app.js
const store = new Vuex.Store({ state:{ todos:[] }, mutations:{ ... }, actions:{ ... }, getters:{ yizuo:function(state){ return state.todos.filter(item => { return item.done == true //true表示已作 }) }, weizuo:function(state){ return state.todos.filter(item => { return item.done == false //false表示未作 }) } } });
App.vue
<template> <div> <div> <input type="text" v-model.trim="txt"> <button @click="add">新增</button> </div> <ul> <li v-for="item of todos" is="TodoLi" :item="item"></li> </ul> <div> 所有:{{$store.state.todos.length}}個事項<br> 已作:{{$store.getters.yizuo.length}}個完成事項<br> 未作:{{$store.getters.weizuo.length}}個代辦事項<br> </div> <div> <button @click="all">查看所有</button> <button @click="yizuo">查看已作</button> <button @click="weizuo">查看未作</button> </div> </div> </template> <script> import todoli from './components/TodoLi.vue' export default { data() { return { txt: '', state: 'all' } }, computed: { todos() { if(this.state == 'all'){ return this.$store.state.todos }else if(this.state == 'yizuo'){ return this.$store.getters.yizuo }else if(this.state == 'weizuo'){ return this.$store.getters.weizuo } } }, methods: { all() { this.state = 'all' }, yizuo() { this.state = 'yizuo' }, weizuo() { this.state = 'weizuo' } } } </script>
全部業務都已經完成,可是因爲組件和數據太亂,下面開始拆分store。
咱們都知道vuex是vue用來集中管理狀態的容器(管理全局的狀態),實現不一樣組件之間相互的數據訪問。咱們說一下vuex拆分store以及多模塊管理。若是一個項目很是大的話狀態就會很是的多,若是不進行分類處理,全部的狀態都維護在一個state裏面的話,狀態管理就會變得很是的混亂,這樣很是不利於項目的後期維護。如今前端推崇模塊化開發,爲的就是提升開發效率和維護效率,避免重複工做。那麼vuex是怎麼樣解決這個問題的呢?這個時候咱們今天要講的主角modules就要閃亮登場了。
第一步:將main.js中的store拆分到一個js文件中。
export const storeObj = { state:{ ... }, mutations:{ ... }, actions:{ ... }, getters:{ ... } }
將store中的index.js在main.js中引入
import {storeObj} from "./store/index.js"; const store = new Vuex.Store(storeObj);
第二步:拆分state、mutations、actions、getters
給他們分別建立單獨的js文件,默認暴露
export default { }
能夠將咱們定義的這些對象加入到Vuex的store中
在store中index.js用import引入:
import state from "./state.js"; import mutations from "./mutations.js"; import actions from "./actions.js"; import getters from "./getters.js"; export const storeObj = { state:{ ...state }, mutations:{ ...mutations }, actions:{ ...actions }, getters:{ ...getters } }
因爲沒裝翻譯「...」對象解構語法,會報錯:
npm install --svae-dev babel-plugin-transform-object-rest-spread
配置webpack.config.js
{ test: /\.js?$/, //解析的時候匹配到的都是js loader: "babel-loader", //翻譯字典 options: { presets: ["es2015","ES2015"], plugins: ["transform-object-rest-spread"] } },
配置完成後就能夠識別「...」解構了。
至此,還沒拆完,使用常量代替mutations集合actions的type名字
新建一個types.js文件,在裏面存常量(大寫字母的方法)
注意:把這些常量放到單獨的文件中可讓你的代碼合做者對整個app包含mutation和actions一目瞭然。
用不用常量代替取決於你--在須要多人協做的大型項目中,這會頗有幫助,可是若是你不喜歡,徹底能夠不這麼作。
export const GETALL = "GETALL"; export const DEL = "DEL"; export const ADD = "ADD"; export const CHANGETITLE = "CHANGETITLE"; export const CHANGEDONE = "CHANGEDONE";
暴露常量的名字後,分別在mutations和actions的js文件中使用這些來代替:
mutations.js
import {GETALL,DEL,ADD,CHANGETITLE,CHANGEDONE} from "./types.js"; export default { [GETALL](state, payload) { }, [DEL](state, payload) { }, [ADD](state, payload) { }, [CHANGETITLE](state, payload) { }, [CHANGEDONE](state, payload) { } }
actions.js
import {GETALL,DEL,ADD,CHANGETITLE,CHANGEDONE} from "./types.js"; export default { async [GETALL]({ commit }) { }, async [DEL]({ commit }, payload) { }, async [ADD]({ commit }, payload) { }, async [CHANGETITLE]({ commit }, payload) { }, async [CHANGEDONE]({ commit }, payload) { } }
注意:上方mutations和actions中的[types.ADD]寫法,由於types.ADD是一個對象,因此不能直接當作函數名來寫,須要用到ES2015風格的計算屬性命名功能來使用一個常量做爲函數名,才能使用。
https://vuex.vuejs.org/zh/guide/mutations.html
好比在Apache中演示:
<html> <head> <title>Document</title> </head> <body> <script src="jquery-3.3.1.min.js"></script> <script> $.get("http://127.0.0.88/a.txt" , function(data){ console.log(data); }); </script> </body> </html>
試圖在127.0.0.1請求127.0.0.88/a.txt的JSON數據,會報錯:
瀏覽器會阻止對ip地址不一樣,或者端口號不一樣的數據請求。
此時咱們必需要進行請求,就是跨域技術。
<html> <head> <title>Document</title> </head> <body> <script> function haha(info){ console.log(info); } </script> <script src="http://127.0.0.88/a.txt"></script> </body> </html>
在頁面上定義一個函數,而後用script標籤引入這個語句,執行這個語句。此時數據就經過函數的實參和形參的結合,傳入了頁面。script沒有跨域限制的,能夠輕鬆src引入其餘ip地址的js文件。
JSONP叫作JSON 和 Padding(補白)
咱們寫一個接口,這個接口不是一個JSON,而是一個語句,這個語句是函數的調用。
升級:把a.txt改成a.php(這個文件不須要會,由於是後端的事情)
<?php $callback = $_GET["callback"]; //獲取get請求 echo $callback . '({"a" : 100 })';//JSON參數 ?>
點擊按鈕再發出JSONP跨域請求。
本質上是點擊按鈕的瞬間,建立了一個script標籤,script標籤的src指向了咱們剛剛寫的那個接口,那個接口是函數的調用。咱們快速定義這個函數,使得src引入的js可以調用這個函數,從而經過實參和形參的結合,將數據傳入頁面。
<script> $("button").click(function(){ //建立script標籤 var $o = $("<script><\/script>"); //建立一個src $o.attr("src" , "http://127.0.0.88/a.php?callback=xixi"); //定義全局函數 window.xixi= function(data){ //接收到數據的回調函數 console.log(data); } //上樹 $("head").append($o); //下樹 $o.remove(); }); </script>
但實際上不用這麼麻煩,jQuery會自動幫咱們發出jsonp跨域:
<html lang="en"> <head> <title>Document</title> </head> <body> <button>按我發出請求</button> <script> $("button").click(function(){ $.ajax({ "dataType" : "JSONP" , "url" : "http://127.0.0.88/a.php", "success" : function(data){ console.log(data); } }) }); </script> </body> </html>
jQuery會隨機生成一個函數名。
原理和咱們寫的同樣的,都是:
1)瞬間建立一個內部函數
2)瞬間建立一個script標籤,src指向咱們的url地址
3)瞬間上樹
4)瞬間下樹
以前咱們項目的數據和前端的文件都是同源的(就是在同一個接口下)。
可是,工做中,必定是要跨域請求數據的。
好比咱們的前端項目運行在8080端口,要請求3000端口的數據,就是跨域。
事實上,工做中,模擬接口必定是不一樣ip的,模擬接口運行在辦公室的局域網上的。
每一個人的電腦都是同一個局域網的,後臺哥哥會給你一個後端接口文檔,接口在演示的時候,頗有多是3000、8000等等。但你的前端項目跑在webpack-dev-server的8080端口,就涉及到跨域請求數據了。
建立一個後端文件夾(server_side)和前端項目文件夾(Vue_study):
前端後端共同跑:後端3000,前端8080
app.js
var express = require("express"); var app = express(); app.get("/a", function(req,res){ // res.json({"a":100}); res.jsonp({"a":100}); //jsonp()能自動獲得callback參數請求 }) app.listen(3000);
http://127.0.0.1:3000/a?callback=haha
App.vue
<template> <div> <h1>首頁</h1> <button @click="addServer">請求數據</button> </div> </template> <script> export default { methods:{ addServer(){ $.ajax({ dataType:"JSONP", url: "http://127.0.0.1:3000/a", success:function(data){ console.log(data) } }) } } }; </script>
面試想要回答的好,看下面文章:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
http://www.ruanyifeng.com/blog/2016/04/cors.html
跨域資源共享(CORS,Cross-Origin Resource Sharing)機制容許Web應用服務器進行跨域訪問控制,從而使得跨域數據傳輸得以安全進行。瀏覽器支持在API容器中(例如XMLHttpRequest或fetch)使用CORS,以下降跨域HTTP請求所帶來的風險。
說白了,就是在HTTP下響應的頭部加一句話。
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制
咱們在後端通常就加Access-Control-Allow-Origin 值爲「*」
問題:8080的前端頁面請求3000後端的頁面,是誰禁止的?是瀏覽器禁止的,爲了安全。此時就要寫一個HTTP下行響應頭部,來告訴瀏覽器,此次請求是容許的,這是最簡單的跨域方法,可是IE8纔開始兼容。
app.js後端:
var express = require("express"); var app = express(); app.get("/a", function(req,res){ //表示容許任何域名來源的請求 res.setHeader("Access-Control-Allow-Origin", "*"); res.json({a:100}); }) app.listen(3000);
App.vue此時在前端項目中就能夠隨意跨域:
<template> <div> <h1>首頁</h1> <button @click="addServer">請求數據</button> </div> </template> <script> export default { methods:{ addServer(){ $.get("http://127.0.0.1:3000/a", function(data){ console.log(data) }) } } } </script>
「代理」就是偷數據。
拿PHP作例子,實現一下偷百度首頁(瞭解便可)
<?php echo file_get_contents("http://www.baidu.com/"); ?>
運行tou.php就直接是百度首頁了。
好比京東充話費接口,能夠被後端偷來:
而後在前端項目中使用:
<body> <h1>手機歸屬地查詢(業績最快,徹底免費)</h1> <input type="text" id="tel"> <button>查詢</button> </body> <script type="text/javascript" src="js/jquery-2.2.4.min.js"></script> <script type="text/javascript"> $("button").click(function(){ var tel = $("#tel").val(); //能夠請求本身服務器的數據,只不過數據由後端tou.php偷回來。 $.get("http://127.0.0.1:8088/tou.php?tel=" + tel, function(data){ console.log(data) }) }); </script>
webpack-dev-server能夠幫咱們偷服務端的數據,美其名曰「代理」。
至關於服務器去「偷數據」,由後端(前端的後端,就是webpack-dev-server)出面,問3000端口要數據
在webpack.config.js中,加幾句話便可實現「代理跨域」。
https://webpack.docschina.org/configuration/dev-server/#devserver-proxy
webpack-dev-server這個小型服務器底層也是express實現的
webpack-dev-server在幫咱們作幾件事:
1)構建app文件夾到/public/all.js去
2)靜態化www文件夾提供了靜態文件的路由
3)代理了127.0.0.1:3000的接口。
4)構建app的時候進行了翻譯
webpack.config.js配置:
var path = require('path'); const {VueLoaderPlugin} = require("vue-loader"); //最新版webpack須要引入此插件 module.exports = { //程序的入口文件 entry: './www/app/app.js', //程序的出口文件(被打包的文件) output: { ... }, //自動監聽 watch:true, mode : "development", //配置webpack的模塊插件 module:{ // 關於模塊配置 ... }, resolve: { ... }, devServer: { proxy: { '/api': { target: 'http://127.0.0.1:3000', //設置你調用的接口域名和端口 //這裏理解成/api代理target中的地址,後面組件中調用接口要使用/api代替 pathRewrite: {'^/api' : ''} } } }, //最新版webpack須要引入此插件 plugins:[ new VueLoaderPlugin() ] };
這些配置都從webpack官網抄的,配置就能夠作項目了,實現接口的請求。
配置好後,重啓 npm run dev,好比3000有一個接口/a,如今將被代理到8080接口的/api/a:
http://127.0.0.1:3000/a這個接口,被「代理」到http://127.0.0.1:8080/api/a
|
|
若是後端app.js出一個這樣的接口:http://127.0.0.1/:3000/a
app.get("/a",function(req,res){ res.json({"a":100}); });
前端app.js就能夠這樣獲取後端的接口:http://127.0.0.1/:8080/api/a
<template> <div> <h1>首頁</h1> <button @click="addServer">請求數據</button> </div> </template> <script> export default { methods : { addServer(){ $.get("http://127.0.0.1:8080/api/a",function(data){ console.log(data); }) } } } </script>
總結:一提起「跨域」,立馬回答他一共有三種方法。
後端app.js提供數據接口:(node app.js運行)
var express = require("express"); var app = express(); app.get("/a" , function(req,res){ res.json({"a":100}); }); app.listen(3000);
前端main.js
import Vue from "vue"; import Vuex from "vuex"; import App from "./App.vue"; import store from "./store"; new Vue({ el:"#app", store, render:(h)=>h(App) })
前端App.vue:
<template> <div> <h1>{{$store.state.counterState.a}}</h1> <button @click="add(1)">加1</button> <button @click="add(2)">加2</button> <button @click="addServer">按我加服務器的數據</button> </div> </template> <script> export default { methods : { add(n){ this.$store.commit("ADD", {n}); }, addServer(){ //異步必須用dispatch this.$store.dispatch("ADDSERVER"); } } } </script>
store中的index.js:
import Vue from "vue"; import Vuex from "vuex"; import createLogger from 'vuex/dist/logger'; import counterState from "./counter/state.js"; import counterMutations from "./counter/mutations.js"; import counterActions from "./counter/actions.js"; Vue.use(Vuex); //全局數據 export default new Vuex.Store({ state: { counterState }, //同步的(commit) mutations: { ...counterMutations }, //異步的(dispatch) actions : { ...counterActions }, plugins: [createLogger()] });
state.js
export default { a: 100 }
mutations.js
export default { ADD(state, payload) { state.counterState.a += payload.n; } }
actions.js
export default { async ADDSERVER({commit}){ //發出異步請求 const {a} = await fetch("/api/a").then(data=>data.json()); //異步函數不能改變state,改變state只有mutations commit("ADD" , {n:a}) //觸發mutation } }