接口文檔地址:
http://toutiao.itheima.net/api.html#u5173u6ce8u7528u62370a3ca20id3du5173u6ce8u7528u62373e203ca3e
項目源碼地址:
https://gitee.com/git640640/news
一、項目初始化--使用vite創(chuàng)建項目
1.1搭建第一個 Vite 項目

你還可以通過附加的命令行選項直接指定項目名稱和你想要使用的模板。例如,要構(gòu)建一個 Vite + Vue 項目,運行:
# npm 7+, extra double-dash is needed:
npm create vite@latest news -- --template vue
安裝結(jié)束,命令提示你項目創(chuàng)建成功,按照命令行的提示在終端中分別輸入:
# 進入你的項目目錄
cd news
# 啟動開發(fā)服務(wù)
npm run dev

Ctrl+鼠標左鍵單擊http://127.0.0.1:5173/進入http訪問地址,如果瀏覽器能打開頁面,說明項目創(chuàng)建成功了。
二、加入 Git 版本管理
幾個好處:
代碼備份
多人協(xié)作
歷史記錄
(1)創(chuàng)建遠程倉庫
GitHub:https://gitee.com/git640640
(2)將本地倉庫推到線上
如果沒有本地倉庫
#創(chuàng)建本地倉庫
git init
#將文件添加到暫存區(qū)
git add .
#提交歷史記錄
git commit '提交日志'
#添加遠程倉庫地址
git remote add origin 你的遠程倉庫地址
#推送提交
git push -u origin master
如果已有本地倉庫
#添加遠程倉庫地址
git remote add origin 你的遠程倉庫地址
#推送提交
git push -u origin master
如果之后項目代碼有了變動需要提交
#將文件添加到暫存區(qū)
git add .
#提交歷史記錄
git commit '提交日志'
#推送提交
git push
三、調(diào)整初始目錄結(jié)構(gòu)
默認生成的目錄結(jié)構(gòu)不滿足我們的開發(fā)需求,所以這里需要做一些自定義改動。
這里主要就是下面的兩個工作:
刪除初始化的默認文件
新增調(diào)整我們需要的目錄結(jié)構(gòu)
將 App.vue 修改為
<!-- 視圖層: html -->
<template>
<router-view></router-view>
</template>
<!-- 邏輯層:js -->
<script setup>
</script>
<style scoped>
</style>
安裝vue-router和less
npm install vue-router
npm install less
3.在src文件夾下新建router/index.js,將 router/index.js 修改為
import { createRouter, createWebHashHistory } from 'vue-router'
// 1、創(chuàng)建路由規(guī)則
const routes = [
]
// 2、創(chuàng)建路由實例
const router = createRouter({
history: createWebHashHistory(),
routes
});
export default router;
4.刪除
src/components/HelloWorld.vue
src/components/Aside.vue
src/components/Main.vue
5.創(chuàng)建以下幾個目錄
src/api 目錄
存儲接口封裝
src/utils 目錄
存儲一些工具模塊
src/styles 目錄
style.less文件,存儲全局樣式
在 main.js 中加載全局樣式 import '~/styles/style.less'
四、引入 Vant 組件庫
Vant 是有贊商城前端開發(fā)團隊開發(fā)的一個基于 Vue.js 的移動端組件庫,它提供了非常豐富的移動端功能組件,簡單易用。

官方文檔:https://vant-contrib.gitee.io/vant/#/zh-CN
安裝
# Vue 3 項目,安裝最新版 Vant
npm i vant
引入組件
方法一:常規(guī)用法
下面是使用 Vant 組件的用法示例:
main.js
import { createApp } from 'vue';
// 1. 引入你需要的組件
import { Button } from 'vant';
// 2. 引入組件樣式
import 'vant/lib/index.css';
const app = createApp();
// 3. 注冊你需要的組件
app.use(Button);
方法二:按需引入組件樣式
在基于 vite、webpack 或 vue-cli 的項目中使用 Vant 時,可以使用 unplugin-vue-components 插件,它可以自動引入組件,并按需引入組件的樣式。
相比于常規(guī)用法,這種方式可以按需引入組件的 CSS 樣式,從而減少一部分代碼體積,但使用起來會變得繁瑣一些。如果業(yè)務(wù)對 CSS 的體積要求不是特別極致,我們推薦使用更簡便的常規(guī)用法。
安裝插件
# 通過 npm 安裝
npm i unplugin-vue-components -D
配置插件
如果是基于 vite 的項目,在 vite.config.js 文件中配置插件:
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from 'unplugin-vue-components/resolvers';
export default {
plugins: [
vue(),
Components({
resolvers: [VantResolver()],
}),
],
};
3.使用組件
完成以上兩步,就可以直接在模板中使用 Vant 組件了,unplugin-vue-components 會解析模板并自動注冊對應(yīng)的組件。
<template>
<van-button type="primary" />
</template>
4.引入函數(shù)組件的樣式
ant 中有個別組件是以函數(shù)的形式提供的,包括 Toast,Dialog,Notify 和 ImagePreview 組件。在使用函數(shù)組件時,unplugin-vue-components 無法自動引入對應(yīng)的樣式,因此需要手動引入樣式。
// Toast
import { showToast } from 'vant';
import 'vant/es/toast/style';
// Dialog
import { showDialog } from 'vant';
import 'vant/es/dialog/style';
// Notify
import { showNotify } from 'vant';
import 'vant/es/notify/style';
// ImagePreview
import { showImagePreview } from 'vant';
import 'vant/es/image-preview/style';
你可以在項目的入口文件或公共模塊中引入以上組件的樣式,這樣在業(yè)務(wù)代碼中使用組件時,便不再需要重復(fù)引入樣式了。
五、移動端 REM 適配
如果需要使用 rem 單位進行適配,推薦使用以下兩個工具:
postcss-pxtorem 是一款 PostCSS 插件,用于將 px 單位轉(zhuǎn)化為 rem 單位
lib-flexible 用于設(shè)置 rem 基準值
下面我們分別將這兩個工具配置到項目中完成 REM 適配。
一、使用lib-flexible 動態(tài)設(shè)置REM基準值(html標簽的字體大?。?/h3>
安裝
npm i -S amfe-flexible
然后在main.js中加載執(zhí)行該模塊
import 'amfe-flexible'
安裝
然后在main.js中加載執(zhí)行該模塊
最后測試:在瀏覽器中切換不同的手機設(shè)備尺寸,觀察 html 標簽 font-size 的變化。


二、使用postcss-pxtorem將px轉(zhuǎn)為rem
安裝
npm install postcss postcss-pxtorem --save-dev
在vite.config.js配置
如果設(shè)計稿的尺寸不是 375,而是 750 或其他大小,可以將 rootValue 配置調(diào)整為:
import postCssPxToRem from 'postcss-pxtorem';
export default defineConfig({
plugins: [vue(),
Components({
resolvers: [VantResolver()],
}),],
css: {
postcss: {
plugins: [
postCssPxToRem({
rootValue({ file }) {
return file.indexOf('vant') !== -1 ? 37.5 : 75;
}, // 1rem的大小
propList: ['*'], // 需要轉(zhuǎn)換的屬性,這里選擇全部都進行轉(zhuǎn)換
})
]
}
},
})
3.配置完畢,重新啟動服務(wù)
最后測試:刷新瀏覽器頁面,審查元素的樣式查看是否將px轉(zhuǎn)化為rem。
轉(zhuǎn)換之后的,可以看到 px 都被轉(zhuǎn)換為了 rem。

需要注意的是:該插件不能轉(zhuǎn)換行內(nèi)樣式中的px,例如 <div style="width: 200px;"></div>
六、將src目錄配置成~
vite.config.js
import path from "path"
export default defineConfig({
resolve:{
alias:{
"~":path.resolve(__dirname,"src")
}
},
})
七、封裝請求模塊
和之前項目一樣,這里我們還是使用 axios 作為我們項目中的請求庫,為了方便使用,我們把它封裝為一個請求模塊,在需要的時候直接加載即可。
安裝
npm i axios
創(chuàng)建 src/utils/request.js
// 請求模塊
import axios from 'axios'
const request = axios.create({
baseURL:'http://toutiao.itheima.net/' //基礎(chǔ)路徑
})
// 請求攔截器
export default request;
我們把每一個請求都封裝成每一個獨立的功能函數(shù),在需要的時候加載調(diào)用,這種做法更便于接口的管理和維護。
八、導(dǎo)入字體圖標




九、配置路由頁面
Tabbar處理

通過分析頁面,我們可以看到,首頁、視頻、消息、我的都使用的是同一個底部標簽欄,我們沒必要在每個頁面中都寫一個,所有為了通用方便,我們可以使用vue router的嵌套路由來處理。
父路由:一個空頁面,包含一個tabbar,中間留子路由出口
子路由:首頁、視頻、消息、我的
一、創(chuàng)建tabbar組件并配置路由
這里主要使用到vant組件:
創(chuàng)建 src/views/layout/index.vue
<!-- 視圖層: html -->
<template>
<div class="layout-container">
<!-- 子路由的出口 -->
<router-view></router-view>
<!-- 標簽導(dǎo)航欄 -->
<van-tabbar route="true" v-model="active" active-color="rgb(197, 66, 34)">
<van-tabbar-item replace to="/home" icon="wap-home-o"
>首頁</van-tabbar-item
>
<van-tabbar-item replace to="/video" icon="video-o">視頻</van-tabbar-item>
<van-tabbar-item replace to="/news" icon="chat-o">消息</van-tabbar-item>
<van-tabbar-item replace to="/me" icon="user-o"></van-tabbar-item>
</van-tabbar>
</div>
</template>
<!-- 邏輯層:js -->
<script setup>
import { ref } from "vue";
const active = ref(0);
</script>
<style scoped>
</style>
二、分別創(chuàng)建首頁、視頻、消息、我的頁面組件

三、將layout組件配置到一級路由,將首頁、視頻、消息、我的頁面組件配置為layout的子路由
// 1、創(chuàng)建路由規(guī)則
const routes = [
{
path:"/",
component:Layout,
children:[
{
path:"/home",
name:"home",
component:Home,
},
{
path: "/video",
name: "video",
component: Video,
},
{
path: "/news",
name: "news",
component: News,
},
{
path: "/me",
name: "me",
component: Me,
}
]
},
{
path: '/login',
name: 'login',
component: Login
},
]
十、登錄頁面

這里用到的vant組件:
NavBar導(dǎo)航欄:https://vant-contrib.gitee.io/vant/#/zh-CN/nav-bar
Form表單:https://vant-contrib.gitee.io/vant/#/zh-CN/form
Field輸入框:https://vant-contrib.gitee.io/vant/#/zh-CN/field
Button按鈕:https://vant-contrib.gitee.io/vant/#/zh-CN/button
布局結(jié)構(gòu)
src/views/login/index.vue
<!-- 視圖層: html -->
<template>
<div class="login-container">
<van-nav-bar
class="app-nav-bar"
title="登錄"
left-arrow
@click-left="onClickLeft"
/>
<!-- 可以使用 CellGroup 作為容器 -->
<van-form ref="loginForm" @submit="onSubmit">
<van-field
v-model="user.mobile"
name="mobile"
icon-prefix="news"
left-icon="shouji"
placeholder="請輸入手機號"
:rules="userFormRules.mobile"
type="number"
maxlength="11"
/>
<van-field
v-model="user.code"
name="code"
icon-prefix="news"
left-icon="yanzhengma"
placeholder="請輸入驗證碼"
:rules="userFormRules.code"
type="number"
maxlength="6"
>
<template #button>
<van-count-down
v-if="isCountDownShow"
@finish="isCountDownShow = false"
:time="time"
format="ss s"
/>
<van-button
v-else
@click="onSendSms"
native-type="button"
class="send-btn"
size="small"
round
>發(fā)送驗證碼</van-button
>
</template>
</van-field>
<div class="login-btn-wrap">
<van-button type="info" native-type="submit" block class="login-btn"
>登錄</van-button
>
</div>
</van-form>
</div>
</template>
<!-- 邏輯層:js -->
<script setup>
</script>
<style lang="less" scoped>
.login-container {
.login-btn-wrap {
padding: 37px 27px;
.login-btn {
background-color: rgb(197, 66, 34);
color: #fff;
border: none !important;
}
}
.send-btn {
background-color: #ededed;
color: #666;
}
}
</style>
實現(xiàn)基本登錄功能
思路:
注冊點擊登錄事件
獲取表單數(shù)據(jù)
表單驗證
發(fā)請求提交
根據(jù)請求結(jié)果做下一步處理
一、根據(jù)接口要求綁定獲取表單數(shù)據(jù)

1、在src/views/login/index.vue添加user響應(yīng)式數(shù)據(jù)字段
<script setup>
import { reactive } from "vue";
const user = reactive({
mobile: "",
code: "",
});
</script>
2、在表單中使用v-model綁定對應(yīng)數(shù)據(jù)
<van-field
v-model="user.mobile"
name="mobile"
placeholder="請輸入手機號"/>
<van-field
v-model="user.code"
name="code"
placeholder="請輸入驗證碼"
type="number"
>
二、請求登錄
創(chuàng)建 src/api/user.js 封裝請求方法
import request from '~/utils/request'
// import store from '~/store'
// 登錄注冊驗證
export const login = data => {
return request({
method: 'POST',
url: '/v1_0/authorizations',
data
})
}
2.表單驗證
登錄狀態(tài)提示
Vant 中內(nèi)置了Toast 輕提示組件,可以實現(xiàn)移動端常見的提示效果。
forbidClick:是否禁止背景點擊是否禁止背景點擊


<script setup>
import {
showLoadingToast,
showSuccessToast,
showFailToast,
showToast,
} from "vant";
import "vant/es/toast/style";
showLoadingToast({
message: "登錄中...",
forbidClick: true,
duration: 0,
});
showSuccessToast("登陸成功");
showFailToast("登陸失敗");
</script>
給van-field組件配置rules驗證規(guī)則
當表單提交的時候會自動觸發(fā)表單驗證
如果驗證通過,會觸發(fā)submit事件
如果驗證不通過,不會觸發(fā)submit事件

<van-form @submit="onSubmit">
......
<div class="login-btn-wrap">
<van-button type="info" native-type="submit" block class="login-btn">登錄</van-button>
</div>
</van-form>
<script setup>
import { reactive} from "vue";
import { login } from "~/api/user";
const user = reactive({
mobile: "",
code: "",
});
const userFormRules = {
mobile: [
{ required: true, message: "手機號不能為空" },
{ pattern: /1[3|5|7|8|9]\d{9}/, message: "手機號格式錯誤" },
],
code: [
{ required: true, message: "驗證碼不能為空" },
{ pattern: /^\d{6}$/, message: "驗證碼格式錯誤" },
],
};
async function onSubmit() {
showLoadingToast({
message: "登錄中...",
forbidClick: true, // 是否禁止背景點擊
duration: 0, // 持續(xù)展示 toast
});
try {
const res = await login(user)
console.log('登錄成功', res)
showSuccessToast("登陸成功");
} catch (err) {
showFailToast("登陸失敗");
}
}
</script>
3.驗證碼處理
驗證手機號

創(chuàng)建 src/api/user.js 封裝請求方法
// 發(fā)送短信驗證碼
// 每手機號每分鐘1次
export const sendSms = mobile => {
return request({
method: 'GET',
url:`/v1_0/sms/codes/${mobile}`,
})
}
在src/views/login/index.vue中校驗手機號
icon-prefix:圖標類名前綴,等同于 Icon 組件的 class-prefix 屬性
left-icon:左側(cè)圖標名稱或圖片鏈接,等同于 Icon 組件的 name 屬性
validate:驗證表單,支持傳入一個或多個 name 來驗證單個或部分表單項,不傳入 name 時,會驗證所有表單項
<template>
......
<van-form ref="loginForm" @submit="onSubmit">
<van-field
v-model="user.mobile"
name="mobile"
icon-prefix="news"
left-icon="shouji"
placeholder="請輸入手機號"
:rules="userFormRules.mobile"
type="number"
maxlength="11"
/>
<van-field
v-model="user.code"
name="code"
icon-prefix="news"
left-icon="yanzhengma"
placeholder="請輸入驗證碼"
:rules="userFormRules.code"
type="number"
maxlength="6"
>
<template #button>
<van-count-down
v-if="isCountDownShow"
@finish="isCountDownShow = false"
:time="time"
format="ss s"
/>
<van-button
v-else
@click="onSendSms"
native-type="button"
class="send-btn"
size="small"
round
>發(fā)送驗證碼</van-button
>
</template>
</van-field>
......
</van-form>
</div>
</template>
// 1. 校驗手機號
const loginForm = ref(null);
async function onSendSms() {
try {
await loginForm.value.validate("mobile");
} catch (err) {
return console.log("驗證失敗", err);
}
}
使用倒計時組件
https://vant-contrib.gitee.io/vant/#/zh-CN/count-down
time:倒計時時長,單位毫秒·
format:時間格式,通過 format 屬性設(shè)置倒計時文本的內(nèi)容
finish:倒計時結(jié)束時觸發(fā)
<van-field
v-model="user.code"
name="code"
icon-prefix="news"
left-icon="yanzhengma"
placeholder="請輸入驗證碼"
:rules="userFormRules.code"
type="number"
maxlength="6"
>
<template #button>
<van-count-down
v-if="isCountDownShow"
@finish="isCountDownShow = false"
:time="time"
format="ss s"
/>
<van-button
v-else
@click="onSendSms"
native-type="button"
class="send-btn"
size="small"
round
>發(fā)送驗證碼</van-button
>
</template>
</van-field>
<script setup>
const isCountDownShow = ref(false);
</script>
發(fā)送驗證碼

1、在 api/user.js 中添加封裝數(shù)據(jù)接口
// 發(fā)送短信驗證碼
// 每手機號每分鐘1次
export const sendSms = mobile => {
return request({
method: 'GET',
url:`/v1_0/sms/codes/${mobile}`,
})
}
2、給發(fā)送驗證碼按鈕注冊點擊事件
<van-button
v-else
@click="onSendSms"
native-type="button"
class="send-btn"
size="small"
round
>發(fā)送驗證碼</van-button
>
3、發(fā)送處理
const time = ref(1000 * 10);
async function onSendSms() {
// 1. 校驗手機號
try {
await loginForm.value.validate("mobile");
} catch (err) {
return console.log("驗證失敗", err);
}
// 2. 驗證通過,顯示倒計時
isCountDownShow.value = true;
// 3. 請求發(fā)送驗證碼
try {
await sendSms(user.mobile);
showToast("發(fā)送成功");
} catch (err) {
// 發(fā)送失敗,關(guān)閉倒計時
isCountDownShow.value = false;
if (err.response.status === 429) {
showToast("發(fā)送太頻繁了,請稍后重試");
} else {
showToast("發(fā)送失敗,請稍后重試");
}
}
}
十一、處理用戶Token

Token是用戶登錄成功之后服務(wù)端返回的一個身份令牌,在項目中的多個業(yè)務(wù)中需要使用到:
訪問需要授權(quán)的Api接口
校驗頁面的訪問權(quán)限
...
但是我們只有在第一次用戶登陸成功之后才能拿到Token。
所以為了能在其他模塊中獲取到Token數(shù)據(jù),我們需要把它存儲到一個公共的位置,方便隨時取用。
往哪兒存?
本地存儲
獲取麻煩
數(shù)據(jù)不是響應(yīng)式的
Vuex容器(推薦)
獲取方便
響應(yīng)式的
引入vuex狀態(tài)管理用戶信息
Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式 + 庫。它采用集中式存儲
管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變
化
1、安裝
官網(wǎng) https://vuex.vuejs.org/zh/
npm install vuex@next --save
2、在 src/store/index.js 中配置vuex文件
import { createStore } from 'vuex'
export default createStore({
state: {
user:JSON.parse(window.localStorage.getItem(TOKEN_KEY))
},
mutations: {
setUser(state, data) {
state.user = data
// 為了防止刷新丟失,我們需要把數(shù)據(jù)備份到本地存儲
window.localStorage.setItem(TOKEN_KEY,JSON.stringify(state.user))
},
},
actions: {
},
modules: {
}
})
3、全局引用vuex文件
//導(dǎo)入文件
import store from './store'
//掛載使用
createApp(App).use(store)
4、登錄成功以后將后端返回的 token 相關(guān)數(shù)據(jù)存儲到容器中
async function onSubmit() {
showLoadingToast({
message: "登錄中...",
forbidClick: true, // 是否禁止背景點擊
duration: 0, // 持續(xù)展示 toast
});
try {
const res = await login(user);
store.commit("setUser", res.data.data);
console.log(data.data);
showSuccessToast("登陸成功");
} catch (err) {
showFailToast("登陸失敗");
}
}
十二、優(yōu)化封裝本地存儲操作模塊
1、創(chuàng)建 src/utils/storage.js 模塊。
// 封裝本地存儲操作模塊
// 1.存儲數(shù)據(jù)
export const setItem=(key,value)=>{
// 將數(shù)組、對象類型的數(shù)據(jù)轉(zhuǎn)化為Json格式字符串進行存儲
if(typeof value==='object'){
value=JSON.stringify(value)
}
window.localStorage.setItem(key,value)
}
// 2.獲取數(shù)據(jù)
export const getItem=key=>{
const data=window.localStorage.getItem(key)
try {
return JSON.parse(data)
} catch (error) {
return data
}
}
// 3.刪除數(shù)據(jù)
export const removeItem=key=>{
window.localStorage.removeItem(key)
}
2、在 src/store/index.js 中
import { createStore } from 'vuex'
import { getItem, setItem } from '~/utils/storage.js'
const TOKEN_KEY = 'NEWS_USER'
export default createStore({
state: {
user: getItem(TOKEN_KEY),
// user:JSON.parse(window.localStorage.getItem(TOKEN_KEY))
},
mutations: {
setUser(state, data) {
state.user = data
// 為了防止刷新丟失,我們需要把數(shù)據(jù)備份到本地存儲
// window.localStorage.setItem(TOKEN_KEY,JSON.stringify(state.user))
setItem(TOKEN_KEY, state.user)
},
},
actions: {
},
modules: {
}
})
3、在src/views/login/index.vue中
<script setup>
import { useStore } from "vuex";
import { useRouter } from "vue-router";
const store = useStore();
const router = useRouter();
async function onSubmit() {
showLoadingToast({
message: "登錄中...",
forbidClick: true, // 是否禁止背景點擊
duration: 0, // 持續(xù)展示 toast
});
try {
// commit 和dispatch的區(qū)別在于commit是提交mutatious的同步操作,dispatch是分發(fā)actions的異步操作
const { data } = await login(user);
store.commit("setUser", data.data);
console.log(data.data);
showSuccessToast("登陸成功");
router.push("/home");
} catch (err) {
showFailToast("登陸失敗");
}
}
</script>

十三、關(guān)于Token過期問題

登錄成功之后后端會返回兩個Token:
token:訪問令牌,有效期2小時
refresh_token:刷新令牌,有效期14天,用于訪問令牌過期之后重新獲取新的令牌
我們的項目接口中設(shè)定Token有效期2小時,超過有效期服務(wù)端會返回401表示Token無效或過期了。
為什么過期時間這么短?
為了安全,例如Token被別人盜用
過期了怎么辦?
讓用戶重新登錄,用戶體驗太差了
使用refresh_token解決token過期
十四、Vuex五個屬性和使用方法
state:是放置所有公共狀態(tài)的屬性,如果你有一個公共狀態(tài)數(shù)據(jù),你只需要定義在state對象中。state是vuex的基本數(shù)據(jù),用來存儲變量;
// 引入庫
import Vuex from 'vuex'
// 安裝 vuex
Vue.use(Vuex)
// 初始化vuex對象
const store = new Vuex.Store({
state: {
// 管理數(shù)據(jù)
count: 0
}
})
組件中可以使用this.$store獲取到vuex中的store對象實例,可通過state屬性獲取count。
<template>
<div>
<div> state的數(shù)據(jù):{{ $store.state.count }}</div>
</div>
<template>
<script>
// 安裝完 vuex 會在組件中注入一個 $store 的變量
created() {
console.log(this.$store.state.count);
}
</script>
getters:從基本數(shù)據(jù)(state)派生的數(shù)據(jù),相當于state的計算屬性;
除了state之外,有時候還需要從state中派生出一些狀態(tài),這些狀態(tài)是依賴state的,此時會用到getters,例如對列表進行過濾并計數(shù):
const store = new Vuex.Store({
state: {
list: [1,2,3,4,5,6,7,8,9,10]
},
getters: {
// getters函數(shù)的第一個參數(shù)是 state
// 必須要有返回值
filterList: state => state.list.filter(item => item > 5)
}
})
mutations:提交更新數(shù)據(jù)的方法,必須是同步的(如果需要異步使用action)。每個mutation都有一個字符串的事件類型(type)和一個回調(diào)函數(shù)(handler)?;卣{(diào)函數(shù)就是我們實際進行狀態(tài)更改的地方,并且它會接受state作為第一個參數(shù),提交載荷作為第二個參數(shù)。
// ...
mutations: {
addCount(state, data) {
state.count += data
}
你可以向 store.commit 傳入額外的參數(shù),即 mutation 的 載荷(payload)
// ...
<button @click="$store.commit('addCount',10)>
count 增加
</button>
action:和mutation的功能大致相同,不同之處在于:
action提交的是mutation,而不是直接變更狀態(tài)
action可以包含任意異步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
addCount(state) {
state.count++
}
},
actions: {
addCount(store) {
store.commit('addCount')
}
}
})
action函數(shù)接受一個與store實例具有相同方法和屬性的context對象,因此你可以調(diào)用context.commit提交一個mutation,或者通過context.state和context.getter。
實踐中,我們會經(jīng)常用到ES2015的參數(shù)解構(gòu)來簡化代碼:
actions: {
addCount({ commit }) {
commit('addCount')
}
}
分發(fā)action文章來源:http://www.zghlxwxcb.cn/news/detail-485983.html
store.dispatch('addCount')
5.modules:模塊化vuex,可以讓每一個模塊擁有自己的state、mutation、action、getters,使結(jié)構(gòu)非常清晰,方便管理。文章來源地址http://www.zghlxwxcb.cn/news/detail-485983.html
到了這里,關(guān)于vite+vant+vue3新聞客戶端app(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!