簡單的管理後臺基本上就是數據的增刪改查。主要就是 列表 + form 表單。每一個頁面的邏輯基本上都相同。不一樣的地方就是每一個頁面須要調用的具體 API 及參數。vue
之前 vue2 的時候最簡單的作法是寫出來一個頁面的邏輯,而後直接 copy 到各個頁面中,修改 API 及參數便可。高級一點的是利用 mixin
函數,將可複用邏輯抽離,每一個頁面引入 mixin
。react
vue3 以後新增了composition API
。本文就是利用composition API
,將可複用的邏輯抽離到composition API
中,並引入ts,實現一個簡單的管理後臺功能。webpack
首先須要將 @vue/cli 升級到最新版。本文用的是4.5.6版本。ios
vue create admin cd admin npm run serve
create選擇手動選擇Manually select features
,會有一些交互性的選擇,是否要安裝router、vuex
等選項,空格能夠切換是否選中。咱們選中TypeScript、Router、Vuex、CSS Pre-processors
。git
咱們利用axios + axios-mock-adapter + mockjs
來進行接口請求、接口模擬及假數據生成,接下來再安裝這幾個包。github
npm install axios npm install -D axios-mock-adapter mockjs
假設咱們的項目包含一個 Header,Header 的做用是切換頁面。兩個頁面,分別爲 List 和 About,這兩個頁面都是簡單的列表+增刪改查的操做。web
須要在 router 中增長一個 list 的路由信息。vuex
const routes: Array<RouteRecordRaw> = [ { path: '/', name: 'Home', component: Home, }, { path: '/about', name: 'About', component: () => { return import(/* webpackChunkName: "about" */ '../views/About.vue'); }, }, { path: '/list', name: 'List', component: () => { return import(/* webpackChunkName: "list" */ '../views/List.vue'); }, }, ];
首先把列表頁的結構寫出來,List 和 About 的結構大致類似。npm
<template> <div class='content_page'> <div class='content_body'> <div class='content_button'> <button class='add primary' @click='addItem' title='添加'>添加</button> </div> <div class='content_table'> <table> <thead> <tr> <th v-for='item in thead' :key='item'>{{item}}</th> </tr> </thead> <tbody> <tr v-for='(item, index) in list' :key='item.id'> <td> <span :title='item.id'>{{item.id}}</span> </td> <td> <div v-if='index === currentIndex'> <input v-model='item.name' title='name' /> </div> <span :title='item.name' v-else>{{item.name}}</span> </td> <td :title='item.sex'> <div v-if='index === currentIndex'> <input v-model='item.sex' title='sex' /> </div> <span :title='item.sex' v-else>{{item.sex ? '男' : '女'}}</span> </td> <td :title='item.birth'> <div v-if='index === currentIndex'> <input v-model='item.birth' title='birth' /> </div> <span :title='item.birth' v-else>{{item.birth}}</span></td> <td :title='item.address'> <div v-if='index === currentIndex'> <input v-model='item.address' title='birth' /> </div> <span :title='item.address' v-else>{{item.address}}</span> </td> <td> <div v-if='index === currentIndex'> <button class='primary confirm' @click='confirm(item)' >肯定</button> <button @click='cancel(item)' >取消</button> </div> <span v-else> <span @click='editItem(index)'> edit </span> <span @click='deleteItem(index, item)'>delete</span> </span> </td> </tr> </tbody> </table> </div> </div> </div> </template>
其中用到了addItem、editItem、deleteItem、confirm、cancel
這幾個方法,每一個列表頁的這幾個方法功能都是相同的,惟一的不一樣就是請求的 API,咱們能夠將這幾個 API 作爲參數,將增刪改查的方法提取到setup
函數中,作到複用。接下來就來到重點的composition API
。axios
import { ref, onMounted } from 'vue'; import {ItemType, FetchType, DeleteType, AddType, EditType} from '../../types/index'; export const compositionApi = ( fetchApi: FetchType, deleteApi: DeleteType, confirmAddApi: AddType, confirmEditApi: EditType, itemData: ItemType, ) => { const currentIndex = ref<number | null>(null); const list = ref([{}]); const getList = () => { fetchApi().then((res: any) => { list.value = res.data.list; }); }; const addItem = () => { list.value.unshift(itemData); currentIndex.value = 0; }; const editItem = (index: number) => { currentIndex.value = index; }; const deleteItem = (index: number, item: ItemType) => { deleteApi(item).then(() => { list.value.splice(index, 1); // getList(); }); }; const cancel = (item: ItemType) => { currentIndex.value = null; if (!item.id) { list.value.splice(0, 1); } }; const confirm = (item: ItemType) => { const api = item.id ? confirmEditApi : confirmAddApi; api(item).then(() => { getList(); cancel(item); }); }; onMounted(() => { getList(); }); return { list, currentIndex, getList, addItem, editItem, deleteItem, cancel, confirm, }; }; export default compositionApi;
接下來就是在 List 和 About 頁面中的setup方法中引入便可。
<script lang='ts'> import axios from 'axios'; import { defineComponent, reactive } from 'vue'; import { compositionApi } from '../components/composables/index'; import {ItemType} from '../types/index'; const ListComponent = defineComponent({ name: 'List', setup() { const state = reactive({ itemData: { id: '', name: '', sex: 0, birth: '', address: '', }, }); const fetchApi = () => { return axios.get('/users'); }; const deleteApi = (item: ItemType) => { return axios.post('/users/delete', { id: item.id }); }; const confirmAddApi = (item: ItemType) => { return axios.post('/users/add', { name: item.name, birth: item.birth, address: item.address, }); }; const confirmEditApi = (item: ItemType) => { return axios.post('/users/edit', { id: item.id, name: item.name, birth: item.birth, address: item.address, }); }; const localPageData = compositionApi(fetchApi, deleteApi, confirmAddApi, confirmEditApi, state.itemData); return { state, ...localPageData, }; }, data() { return { thead: [ 'id', 'name', 'sex', 'birth', 'address', 'option', ], }; } });
這樣 List 頁面的邏輯基本上就完成了。一樣,About 頁面的邏輯也就完成了,不一樣的就是在 About 頁面更改一下接口請求的地址。
在vue3以前,代碼複用的話通常都是用mixin
,可是mixin
相比於composition API
的劣勢,在官網中的解釋以下:
mixin
很容易發生衝突:由於每一個特性的屬性都被合併到同一個組件中,因此爲了不 property名衝突和調試,你仍然須要瞭解其餘每一個特性。mixin
傳遞任何參數來改變它的邏輯,這下降了它們在抽象邏輯方面的靈活性項目中用到的一些 TS 接口的定義、模擬數據及接口請求本文中沒有具體介紹,若是想了解的話能夠去看看源碼。
戳這裏:vue3_ts_admin