Vue3 | VueCli、node.js安裝文虏、nrm切換鏡像源侣诺、vue項目結(jié)構(gòu)解讀、Router詳解氧秘、VueX詳解

完整原文地址見簡書

更多完整Vue筆記目錄敬請見《前端 Web 筆記 匯總目錄(Updating)》



本文內(nèi)容提要

  • VueCli部分
    • 首先需要安裝nodejs
    • 安裝完node會自動配套npm
    • 使用npm install nrm -g用于調(diào)整 鏡像源年鸳,方便后續(xù)下載依賴
    • 這邊使用淘寶鏡像
    • npm uninstall vue-cli -g 檢查并清除 多余的舊版本
    • 使用npm install -g @vue/cli[@版本號]安裝 腳手架
    • 使用 腳手架 Vue Cli,從 創(chuàng)建項目 到 運(yùn)行項目 的過程
    • 退出之后丸相,把剛剛創(chuàng)建的項目拉進(jìn)VSCode搔确,使用VSCode啟動項目
  • 初始項目結(jié)構(gòu)解讀
    • 源代碼在src下,main.js是入口
    • App.vue文件 簡讀
    • 關(guān)于HelloWorld.vue文件
    • 單文件組件 的含義
  • 基于工程實現(xiàn)TODOList案例 --- 單組件版[App.vue]
  • 基于工程實現(xiàn)TODOList案例 --- 父子組件版[App.vue灭忠、ListItem.vue]
  • Vue-Router部分
    • 在代碼中使用Router
    • Router的作用 及 簡述
    • 首先看一下App.vue根組件怎么寫
    • 解析一下這個多出來的 router/index.js 文件
    • view目錄下的文件
    • 例程膳算,拓展一個Router頁面
    • 補(bǔ)充:Router路由懶加載語法糖 簡述 與例程實戰(zhàn)
  • VueX部分
    • 首先需要創(chuàng)建項目
    • --- 特性配置:
    • package.json文件
    • VueX簡述
    • VueX 框架的引入、數(shù)據(jù)的定義 以及 在組件中的使用
    • 在Home.vue中 使用這個 VueX提供的 全局?jǐn)?shù)據(jù)字段:
    • 如何在任一組件中 修改 VueX的 數(shù)據(jù)
    • VueX的異步操作 同步操作
    • 帶參數(shù)地 修改VueX數(shù)據(jù)
    • VueX修改數(shù)據(jù) 流程設(shè)計的理解
    • 安裝弛作、使用axios發(fā)送ajax請求
    • 把上例的axios請求 封裝到 actions中


VueCli部分

首先需要安裝nodejs

參考博客:
--- Install Node.js
--- Node.js 安裝配置


安裝完node會自動配套npm


使用npm install nrm -g用于調(diào)整 鏡像源涕蜂,方便后續(xù)下載依賴

安裝完了注意,
C:\Users\凌川江雪\AppData\Roaming\npm\nrm -> C:\Users\凌川江雪\AppData\Roaming\npm\node_modules\nrm\cli.js乃是依賴的安裝代碼路徑映琳;

nrm ls可以切換鏡像源:

其他命令如圖机隙,安裝后自然可以看到;

安裝后使用時萨西,你可能遇到這個問題:

D:\OK\nodejsOther>nrm ls
internal/validators.js:124
   throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
   ^

[TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type >string. Received undefined
 at validateString (internal/validators.js:124:11)
 at Object.join (path.js:375:7)
 at Object.<anonymous> (C:\Users\凌川江雪>\AppData\Roaming\npm\node_modules\nrm\cli.js:17:20)
 at Module._compile (internal/modules/cjs/loader.js:1063:30)
 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
 at Module.load (internal/modules/cjs/loader.js:928:32)
 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
 at internal/main/run_main_module.js:17:47
] {
 code: 'ERR_INVALID_ARG_TYPE'
}

解決方案參考——nrm報錯 [ERR_INVALID_ARG_TYPE] 解決方法


這邊使用淘寶鏡像


npm uninstall vue-cli -g 檢查并清除 多余的舊版本


使用npm install -g @vue/cli[@版本號]安裝 腳手架

腳手架沉淀了許多最佳實踐有鹿,
可以借助它快速生成Vue工程,包括 項目目錄組織谎脯、webpack打包配置等葱跋;


使用 腳手架 Vue Cli,從 創(chuàng)建項目 到 運(yùn)行項目 的過程

命令:vue create [項目名]
vue create demo-pro穿肄;
運(yùn)行創(chuàng)建命令之后年局,工具會詢問創(chuàng)建方式:

這里先選第三個,手動選擇創(chuàng)建項目需要的特性咸产,
接著矢否,進(jìn)入選擇特性界面:
用空格進(jìn)行選擇,回車進(jìn)行確定脑溢,
這里選擇以上三個特性即可僵朗,然后回車:
選擇3.x的Vue版本赖欣,回車,選擇使用ESLint的方式:
這里選擇第一個验庙,出錯的時候才會觸發(fā)顶吮;
回車確定;

這里是選擇Lint的校驗時機(jī)——保存時校驗還是commit時校驗粪薛,
這里先選擇第一個悴了,回車確定;

這里是選擇要把config文件违寿,放一個單獨的文件里湃交,還是放一個package.json里,
這里先選第一個藤巢;

最后問搞莺,剛剛這一套特性的選擇需不需要保存下來方便后續(xù)使用,這里不保存掂咒;
回車后工程開始創(chuàng)建:

工程創(chuàng)建完成:
進(jìn)入工程目錄才沧,
使用npm run serve啟動工程:
啟動中:
啟動成功,開始運(yùn)行:
使用瀏覽器訪問:
cmd處ctrl + c兩次可以終止運(yùn)行:


退出之后绍刮,把剛剛創(chuàng)建的項目拉進(jìn)VSCode温圆,使用VSCode啟動項目

因為我們無需每次都用cmd去啟動項目;

把剛剛創(chuàng)建的項目拉進(jìn)VSCode录淡,準(zhǔn)備使用VSCode啟動項目:
在VS Code中捌木,使用Terminal欄啟動即可,方便快捷嫉戚!
【剛拉進(jìn)來可能啟動不了,報9009之類的錯澈圈,
這時候重啟一下VSCode就是了彬檀;
如果項目中沒有node_modules
則需先運(yùn)行npm install安裝node_modules依賴K才窍帝!】
運(yùn)行成功:


初始項目結(jié)構(gòu)解讀

注意要在VS code中安裝vetur這個插件,
使得VS可以提供 語法高亮诽偷、提示 等效果:

源代碼在src下坤学,main.js是入口

--- import { createApp } from 'vue'
指明createApp的來源;
--- import App from './App.vue'
指明App實例报慕,來自于當(dāng)前文件夾下的 App.vue文件深浮;
--- createApp(App).mount('#app')
創(chuàng)建實例、掛載實例:


App.vue文件 簡讀

--- <template>標(biāo)簽對的內(nèi)容眠冈,
其實就等價于之前在組件實例中寫的template:鍵模板飞苇;

--- <script>和<style>標(biāo)簽對自然就是js和樣式的“根據(jù)地了”;

--- 其中<script>中的 name指定了根組件實例名,
component這里引入了一個子組件HelloWorld布卡,
子組件從import HelloWorld from './components/HelloWorld.vue'雨让,
可以看出其定義的地方,即 components文件夾目錄下的HelloWorld.vue忿等;

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


關(guān)于HelloWorld.vue文件

看了一下結(jié)構(gòu)栖忠,其實也沒什么特殊的了,
跟上面App.vue的結(jié)構(gòu)大體都是一樣的:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a  target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a  target="_blank" rel="noopener">babel</a></li>
      <li><a  target="_blank" rel="noopener">eslint</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a  target="_blank" rel="noopener">Core Docs</a></li>
      <li><a  target="_blank" rel="noopener">Forum</a></li>
      <li><a  target="_blank" rel="noopener">Community Chat</a></li>
      <li><a  target="_blank" rel="noopener">Twitter</a></li>
      <li><a  target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a  target="_blank" rel="noopener">vue-router</a></li>
      <li><a  target="_blank" rel="noopener">vuex</a></li>
      <li><a  target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a  target="_blank" rel="noopener">vue-loader</a></li>
      <li><a  target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>


單文件組件 的含義

顧名思義贸街,即一個組件就代表了一個組件庵寞,
如上的App.vueHelloWorld.vue都是單文件組件匾浪;
單獨一個文件內(nèi)容皇帮,就是完整的 HTML(<template>) + CSS(<style>) + JS(<script>)結(jié)構(gòu)了;


基于工程實現(xiàn)TODOList案例 --- 單組件版[App.vue]

<template>
  <div>
    <input v-model="inputValue" />
    <button class="button" @click="handleAddItem">提交</button>
  </div>
  <ul>
    <li v-for="(item, index) in list" :key="index">
      {{ item }}
    </li>
  </ul>
</template>

<script>
import { reactive, ref
 } from "vue";

export default {
  name: "App",
  setup() {
    const inputValue = ref("");
    const list = reactive([]);

    const handleAddItem = () => {
      list.push(inputValue.value);
      inputValue.value = "";
    };
    return { list, inputValue, handleAddItem };
  },
};
</script>

<style>
  .button {
    margin-left: 20px;
  }
</style>

運(yùn)行效果:


基于工程實現(xiàn)TODOList案例 --- 父子組件版[App.vue蛋辈、ListItem.vue]

首先需要創(chuàng)建一個子組件單文件:


其代碼:

<template>
  <div class="hello">
    <li>{{ msg }}</li>
  </div>
</template>

<script>
export default {
  name: 'ListItem',
  props: {
    msg: String
  }
}
</script>

<style>
</style>

App.vue:
與上例 主要區(qū)別就是在<script>中引入属拾,
在<template>中修改:

<template>
  <div>
    <input v-model="inputValue" />
    <button class="button" @click="handleAddItem">提交</button>
  </div>
  <ul>
    <list-item v-for="(item, index) in list" :key="index" :msg="item" />
  </ul>
</template>

<script>
import { reactive, ref } from "vue";
import ListItem from "./components/ListItem.vue";

export default {
  name: "App",
  components: { ListItemListItem },
  setup() {
    const inputValue = ref("");
    const list = reactive([]);

    const handleAddItem = () => {
      list.push(inputValue.value);
      inputValue.value = "";
    };
    return { list, inputValue, handleAddItem };
  },
};
</script>

<style>
.button {
  margin-left: 20px;
}
</style>

運(yùn)行效果同上例;


Vue-Router部分

創(chuàng)建帶router的項目


選擇特性的時候要選上Router:
這里暫時不選history mode冷溶,會使用 hash Router渐白,
適配會簡單些:
其他配置:


在代碼中使用Router

創(chuàng)建好工程項目后,同樣把它拉到VScode里面逞频,
可以看到這里的目錄纯衍,
可以看到main.js中,多了一個.use(router)


Router的作用 及 簡述

作用:根據(jù)url的不同苗胀,展示不同的內(nèi)容襟诸;

如下,運(yùn)行項目基协,默認(rèn)urlhttp://localhost:8080/#/歌亲,展示主頁(Home頁):

編寫url——http://localhost:8080/#/about訪問,則展示about頁:


首先看一下App.vue根組件怎么寫

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

<style>
</style>

--- router-link是定義 跳轉(zhuǎn)路由的標(biāo)簽澜驮,
to屬性可以配置url尾部參數(shù)【前部 自動補(bǔ)上 網(wǎng)站根地址】陷揪,
標(biāo)簽內(nèi)容配置顯示的內(nèi)容;
點擊標(biāo)簽內(nèi)容杂穷,即跳轉(zhuǎn)到悍缠,to補(bǔ)全url 指向的頁面!耐量!
如果有寫<router-view/>飞蚓,則不跳轉(zhuǎn),乃顯示在<router-view/>中拴鸵;

--- <router-view/>則是
根據(jù)router-link以及網(wǎng)頁url組成的url路由玷坠,
router/index.js 文件中的 路由對象(如下一節(jié)的routes)里蜗搔,
找到對應(yīng)的組件路由屬性,拿到對應(yīng)的組件文件路徑八堡,
view目錄中找到 對應(yīng)的組件 去顯示樟凄!


解析一下這個多出來的 router/index.js 文件

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

--- createRouter是vue-router的一個函數(shù),用于創(chuàng)建和初始化Router兄渺;
同時這里第二個參數(shù) 使用了路由參數(shù)routes缝龄;

--- 注意 定義routes參數(shù)這里,
path定義 路徑挂谍、name定義 名稱叔壤、component進(jìn)行 組件的引入;
routers里的組件既稱之為component口叙,
也稱之為view炼绘,子組件的單文件都放在view文件夾下;


view目錄下的文件

-- 可以看到Home.vue這里其實引用一個HelloWorld子組件:


例程妄田,拓展一個Router頁面

  • 首先App.vue添加 router-link:
  • views目錄下創(chuàng)建 單文件組件:
  • router/index.js 的Object Array中俺亮,定義一個對應(yīng)的路由元素:

完事,運(yùn)行疟呐,點擊Heheda脚曾,效果:


補(bǔ)充:Router路由懶加載語法糖 簡述 與例程實戰(zhàn)

如上例程中,router/index.js 中的這個寫法启具,
component 這里使用了 import的方式 引入了組件本讥,
這是一種懶加載、異步加載(如模板注釋:lazy-loaded)的方式鲁冯,
即當(dāng)網(wǎng)頁跳到這一頁的時候拷沸,才會加載對應(yīng)的資源文件,否則不加載薯演;

而如 Home頁的加載方式堵漱,
則是普通的常規(guī)加載:

所以,
--- 異步加載的方式:
首頁打開會快點涣仿,節(jié)省不必要的資源占用,
但是在切換到懶加載頁面時示惊,則需要花費一定的額外加載時間好港;

--- 同步加載的默認(rèn)方式:
則可能 一開始打開首頁等頁面 會慢一些,
但是會把其他頁面一開始就加載好米罚,切換的時候會快一點钧汹;

--- 具體選擇哪種方式,就根據(jù)業(yè)務(wù)需要進(jìn)行選擇录择;

...
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/heheda',
    name: 'Heheda',
    component:  () => import(/* webpackChunkName: "about" */ '../views/Heheda.vue')
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
...

試驗拔莱,運(yùn)行上個例程碗降,之后打開瀏覽器測試工具:

跳到Home頁,刷新頁面塘秦,然后清理記錄讼渊,再點擊about頁,
可以看到這個時候頁面才加載about的資源:


VueX部分

首先需要創(chuàng)建項目


--- 特性配置:
老規(guī)矩尊剔,創(chuàng)建項目之后把項目拉進(jìn)VScode啟動與開發(fā)爪幻;

package.json文件


VueX簡述

VueX 其實就是一個數(shù)據(jù)管理框架
它創(chuàng)建了一個全局的须误、唯一的數(shù)據(jù)倉庫挨稿;

當(dāng)一個前端項目特別大的時候,
或者類似 幾十個頁面 同步共享 某部分?jǐn)?shù)據(jù) 的場景京痢,
我們不可能還是用props奶甘、provide、inject等語法去傳遞數(shù)據(jù)祭椰,
這個時候我們需要一個更加完善的數(shù)據(jù)管理方案臭家;


VueX 框架的引入、數(shù)據(jù)的定義 以及 在組件中的使用

main.js中use它:

store /index.js創(chuàng)建倉庫吭产,
這里在state中準(zhǔn)備了一個測試數(shù)據(jù):

在Home.vue中 使用這個 VueX提供的 全局?jǐn)?shù)據(jù)字段:

這里借助computed屬性侣监,
通過this.$store.state.myTestString獲取到 數(shù)據(jù)字段:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <h1>{{myTestString}}</h1>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: 'Home',
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    }
  }
}
</script>

運(yùn)行效果:

在About.vue中也試一下:

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h1>{{myTestString}}</h1>
  </div>
</template>


<script>
export default {
  name: 'About',
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    }
  }
}
</script>

運(yùn)行效果:


如何在任一組件中 修改 VueX的 數(shù)據(jù)

流程總結(jié):
要修改數(shù)據(jù)的組件,
發(fā)起dispatch(事件) --->

store/index.jsactions
dispatch的事件 進(jìn)行 監(jiān)聽 和回調(diào)處理臣淤,
然后發(fā)起一個commit(事件) --->

store/index.jsmutations
commit的事件 進(jìn)行 監(jiān)聽 和回調(diào)處理橄霉,
處理邏輯中,完成對數(shù)據(jù)的修改邑蒋;

--- 首先姓蜂,需要在事件觸發(fā)的函數(shù)里,
派發(fā)一個action医吊,
改變數(shù)據(jù) 這里在About.vue中钱慢,
我們派testChange【這玩意是可以自定義的】的action,
this.$store.dispatch("testChange");

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
export default {
  name: "About",
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    },
  },
  methods: {
    handleClick() {
      this.$store.dispatch("testChange");
    },
  },
};
</script>

--- 接著在store/index.jsactions里卿堂,即這個VueX全局?jǐn)?shù)據(jù)倉庫中束莫,
dispatch的 監(jiān)聽回調(diào)處理,
store/index.js中的actions會響應(yīng)任意組件的dispatch草描;

--- 再接著览绿,
actions里 對應(yīng)的回調(diào)方法中,使用commit('自定義事件名')穗慕,
觸發(fā)一個mutations饿敲,
store/index.js中的mutations
會響應(yīng)actionscommit逛绵;

--- 最后怀各,
store/index.js中的mutations里倔韭,
actionscommit的監(jiān)聽回調(diào),
在對應(yīng)commit的 事件回調(diào)函數(shù)中(如testChange())瓢对,
修改數(shù)據(jù)(如this.state.myTestString = "lueluelue";)即可寿酌;

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange() {
      console.log("mutations --- testChange");
      this.state.myTestString = "lueluelue";
    }
  },
  actions: {
    testChange() {
      console.log("actions --- testChange");
      this.commit('testChange');
    }
  },
  modules: {
  }
})

運(yùn)行:

點擊文本,
可見完成了數(shù)據(jù)的修改沥曹,效果:
點擊到Home頁份名,
可見這邊的數(shù)據(jù)也跟著改變了,
體現(xiàn)了VueX的全局特性


以上是比較完整的步驟妓美,而如果修改數(shù)據(jù)的時候不涉及異步操作僵腺,則可以簡化上述流程

即省略組件的dispatchstore的actions的步驟,
組件直接就commit壶栋,
然后回調(diào)到store的mutations辰如,
直接修改數(shù)據(jù):

運(yùn)行效果基本同上例;


VueX的異步操作 同步操作

VueX建議在mutations中只進(jìn)行立即執(zhí)行的同步操作贵试,
如果要進(jìn)行異步操作琉兜,必須要在actions中進(jìn)行,
也就是要采用上上節(jié)的步驟 進(jìn)行VueX數(shù)據(jù)的修改毙玻;

例程豌蟋,首先需要組件發(fā)起dispatch:


接著在actions中進(jìn)行異步操作:

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange() {
      console.log("mutations --- testChange");
      this.state.myTestString = "lueluelue";
    }
  },
  actions: {
    testChange() {
      setTimeout(() => {
        console.log("actions --- testChange");
        this.commit('testChange');
      }, 2000);
    }
  },
  modules: {
  }
})

運(yùn)行,點擊文本桑滩,兩秒后文本(即背后的數(shù)據(jù))自動改變:


帶參數(shù)地 修改VueX數(shù)據(jù)

--- About.vue
dispatch時梧疲,
傳遞的 第一個參數(shù)為action
第二個參數(shù)為意圖改動的目標(biāo)數(shù)據(jù)參數(shù)

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
export default {
  name: "About",
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    },
  },
  methods: {
    handleClick() {
      this.$store.dispatch("testChange", "xixixihehehe");
    },
  },
};
</script>

--- store/index.js:

--- actions中的 事件回調(diào)函數(shù)运准,自動生成兩個形參幌氮,
第一個為store實例,
第二個為 組件中dispatch 傳遞過來的 數(shù)據(jù)參數(shù)胁澳;

--- mutations的 事件回調(diào)函數(shù)该互,也自動生成兩個形參,
第一個為 state實例韭畸,
它的值是 以Proxy的結(jié)構(gòu)存儲著
回調(diào)當(dāng)前事件處理函數(shù)的時刻 store 數(shù)據(jù)倉庫的 狀態(tài)【即 state屬性】宇智,
第二個為 actions中commit 【同步操作時,也可以是組件中的commit】
傳遞過來的 數(shù)據(jù)參數(shù)胰丁;

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store, str) {
      setTimeout(() => {
        console.log("actions --- testChange");
        console.log("actions --- testChange --- store", store);
        // this.commit('testChange');
        store.commit('testChange', str);
      }, 2000);
    }
  },
  modules: {
  }
})

運(yùn)行普筹,點擊文本,
兩秒后字體改變隘马,效果:


VueX修改數(shù)據(jù) 流程設(shè)計的理解

這樣設(shè)計,
--- 可以把同步操作的邏輯封裝在mutations中處理妻顶,
把異步操作的邏輯封裝在actions中處理酸员;

--- 又可以通過對觸發(fā)事件名自定義蜒车,
對特定的業(yè)務(wù)處理邏輯、修改數(shù)據(jù)代碼塊 做標(biāo)記幔嗦;

--- 如此使得項目可維護(hù)性高酿愧、可拓展性高、可讀性高邀泉,
出問題時容易排查嬉挡,拓展代碼時也比較方便;


在setup【compositionAPI】中使用VueX

--- Home.vue:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h1>{{ myTestString }}</h1>
  </div>
</template>

<script>
import { useStore } from "vuex";
export default {
  name: "Home",
  setup() {
    const store = useStore();
    const myTestString = store.state.myTestString;
    return { myTestString };
  },
};
</script>

運(yùn)行效果:


使用toRefs整理上述代碼
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h1>{{ myTestString }}</h1>
  </div>
</template>

<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "Home",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    return { myTestString };
  },
};
</script>

運(yùn)行效果同上例汇恤;


在About頁中 試試 setup中修改數(shù)據(jù)

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.commit("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  }
};
</script>

--- store/index.js:

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  modules: {
  }
})

運(yùn)行庞钢,到About頁,


點擊文本:
Home頁數(shù)據(jù)同步:


試一下 setup異步處理

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  }
};
</script>

--- store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store, str) {
      setTimeout(() => {
        console.log("actions --- testChange");
        console.log("actions --- testChange --- store", store);
        // this.commit('testChange');
        store.commit('testChange', str);
      }, 2000);
    }
  },
  modules: {
  }
})


使用axios發(fā)送ajax請求

  • 首先需要安裝axios:

找到一個fastmock接口因谎,
https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register基括;
其內(nèi)容:


在About.vue中請求數(shù)據(jù)并顯示:
--- 主要注意要import
--- get方法的參數(shù)為url财岔,訪問數(shù)據(jù)接口风皿;
--- then接收 接口回復(fù);

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
import axios from "axios";
export default {
  name: "About",
  setup() {
    axios
        .get(
          "https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register"
        )
        .then((response) => {
          console.log("response", response);
          const msg = response.data.desc;
          console.log("response.data.desc", msg);
        });

    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  },
};
</script>

運(yùn)行效果:


把上例的axios請求 封裝到 actions中

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  },
};
</script>

--- store/index.js

import { createStore } from 'vuex'
import axios from "axios";

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store) {
      axios
        .get(
          "https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register"
        )
        .then((response) => {
          console.log("response", response);
          const msg = response.data.desc;
          console.log("response.data.desc", msg);
          store.commit('testChange', msg);
        });
    }
  },
  modules: {
  }
})

運(yùn)行:

點擊文本匠璧,兩秒后:







最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桐款,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子夷恍,更是在濱河造成了極大的恐慌魔眨,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裁厅,死亡現(xiàn)場離奇詭異冰沙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)执虹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門拓挥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袋励,你說我怎么就攤上這事侥啤。” “怎么了茬故?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵盖灸,是天一觀的道長。 經(jīng)常有香客問我磺芭,道長赁炎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任钾腺,我火速辦了婚禮徙垫,結(jié)果婚禮上讥裤,老公的妹妹穿的比我還像新娘。我一直安慰自己姻报,他們只是感情好斩个,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布撑蚌。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪太闺。 梳的紋絲不亂的頭發(fā)上愧旦,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天贾虽,我揣著相機(jī)與錄音足绅,去河邊找鬼。 笑死褂傀,一個胖子當(dāng)著我的面吹牛忍啤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仙辟,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼同波,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叠国?” 一聲冷哼從身側(cè)響起未檩,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粟焊,沒想到半個月后冤狡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡项棠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年悲雳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片香追。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡合瓢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出透典,到底是詐尸還是另有隱情晴楔,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布峭咒,位于F島的核電站税弃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凑队。R本人自食惡果不足惜则果,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧短条,春花似錦导匣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赋访。三九已至可都,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚓耽,已是汗流浹背渠牲。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留步悠,地道東北人签杈。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像鼎兽,于是被迫代替她去往敵國和親答姥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355