利用vue3+ts实现管理后台(增删改查)


Posted in Javascript onOctober 30, 2020

 简单的管理后台基本上就是数据的增删改查。主要就是 列表 + form 表单。每个页面的逻辑基本上都相同。不同的地方就是每个页面需要调用的具体 API 及参数。

以前 vue2 的时候最简单的做法是写出来一个页面的逻辑,然后直接 copy 到各个页面中,修改 API 及参数即可。高级一点的是利用 mixin 函数,将可复用逻辑抽离,每个页面引入 mixin。

vue3 之后新增了composition API。本文就是利用composition API,将可复用的逻辑抽离到composition API中,并引入ts,实现一个简单的管理后台功能。

利用@vue/cli创建项目

首先需要将 @vue/cli 升级到最新版。本文用的是4.5.6版本。

vue create admin
cd admin
npm run serve

create选择手动选择Manually select features,会有一些交互性的选择,是否要安装router、vuex等选项,空格可以切换是否选中。我们选中TypeScript、Router、Vuex、CSS Pre-processors。

我们利用axios + axios-mock-adapter + mockjs来进行接口请求、接口模拟及假数据生成,接下来再安装这几个包。

npm install axios
npm install -D axios-mock-adapter mockjs

项目整体框架

假设我们的项目包含一个 Header,Header 的作用是切换页面。两个页面,分别为 List 和 About,这两个页面都是简单的列表+增删改查的操作。

路由

需要在 router 中增加一个 list 的路由信息。

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 的结构大体相似。

<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。

composition API具体实现

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+ts实现管理后台(增删改查)

composition API vs Mixin

在vue3之前,代码复用的话一般都是用mixin,但是mixin相比于composition API的劣势,在官网中的解释如下:

  • mixin很容易发生冲突:因为每个特性的属性都被合并到同一个组件中,所以为了避免 property名冲突和调试,你仍然需要了解其他每个特性。
  • 可重用性是有限的:我们不能向mixin传递任何参数来改变它的逻辑,这降低了它们在抽象逻辑方面的灵活性

源代码

项目中用到的一些 TS 接口的定义、模拟数据及接口请求本文中没有具体介绍,如果想了解的话可以去看看源码。

戳这里:vue3_ts_admin

到此这篇关于利用vue3+ts实现管理后台(增删改查)的文章就介绍到这了,更多相关vue3 TypeScript 管理后台内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
一个加密JavaScript的开源工具PACKER2.0.2
Nov 04 Javascript
JS模板实现方法
Apr 03 Javascript
jquery结合CSS使用validate实现漂亮的验证
Jan 29 Javascript
详解JavaScript中void语句的使用
Jun 04 Javascript
JavaScript编程中window的location与history对象详解
Oct 26 Javascript
Javascript中Date类型和Math类型详解
Feb 27 Javascript
解决vue router使用 history 模式刷新后404问题
Jul 19 Javascript
浅谈关于angularJs中使用$.ajax的注意点
Aug 12 Javascript
实现div内部滚动条滚动到底部和顶部的代码
Nov 15 Javascript
vue点击自增和求和的实例代码
Nov 06 Javascript
详谈vue中router-link和传统a链接的区别
Jul 22 Javascript
vue 子组件修改data或调用操作
Aug 07 Javascript
vue项目页面嵌入代码块vue-prism-editor的实现
Oct 30 #Javascript
解决vue侦听器watch,调用this时出现undefined的问题
Oct 30 #Javascript
vue2.0 watch里面的 deep和immediate用法说明
Oct 30 #Javascript
JavaScript实现轮播图效果
Oct 30 #Javascript
vue组件添加事件@click.native操作
Oct 30 #Javascript
解决removeEventListener 无法清除监听的问题
Oct 30 #Javascript
详解 javascript对象创建模式
Oct 30 #Javascript
You might like
ADODB结合SMARTY使用~超级强
2006/11/25 PHP
php数组函数序列之array_search()- 按元素值返回键名
2011/11/04 PHP
解析CI即CodeIgniter框架在Nginx下的重写规则
2013/06/03 PHP
php数组编码转换示例详解
2014/03/11 PHP
php cli换行示例
2014/04/22 PHP
php中使用session_set_save_handler()函数把session保存到MySQL数据库实例
2014/11/06 PHP
Yii框架数据库查询、增加、删除操作示例
2019/10/14 PHP
让textarea控件的滚动条怎是位与最下方
2007/04/20 Javascript
js中用window.open()打开多个窗口的name问题
2014/03/13 Javascript
js获取url中的参数且参数为中文时通过js解码
2014/03/19 Javascript
纯js实现瀑布流布局及ajax动态新增数据
2016/04/07 Javascript
es6的数字处理的方法(5个)
2017/03/16 Javascript
js学习心得_一个简单的动画库封装tween.js
2017/07/14 Javascript
快速将Vue项目升级到webpack3的方法步骤
2017/09/14 Javascript
nestjs返回给前端数据格式的封装实现
2021/02/22 Javascript
python实现class对象转换成json/字典的方法
2016/03/11 Python
python 字典(dict)按键和值排序
2016/06/28 Python
轻松掌握python设计模式之访问者模式
2016/11/18 Python
TensorFlow2.0:张量的合并与分割实例
2020/01/19 Python
完美解决python针对hdfs上传和下载的问题
2020/06/05 Python
Pytorch 卷积中的 Input Shape用法
2020/06/29 Python
keras.utils.to_categorical和one hot格式解析
2020/07/02 Python
opencv 阈值分割的具体使用
2020/07/08 Python
详解python安装matplotlib库三种失败情况
2020/07/28 Python
PyCharm2020.1.1与Python3.7.7的安装教程图文详解
2020/08/07 Python
魅力惠奢品线上平台:MEI.COM
2016/11/29 全球购物
世界闻名的衬衫制造商:Savile Row Company
2018/07/30 全球购物
联想法国官方网站:Lenovo法国
2018/10/18 全球购物
Helly Hansen工作服美国官方网上商店:为最恶劣的环境
2019/09/04 全球购物
欧舒丹俄罗斯官方网站:L’OCCITANE俄罗斯
2019/11/22 全球购物
建筑个人求职信范文
2014/01/25 职场文书
小学生期末评语大全
2014/04/21 职场文书
关于安全的标语
2014/06/10 职场文书
会计求职信怎么写
2015/03/20 职场文书
学校元旦晚会开场白
2015/05/29 职场文书
销区经理年终述职报告模板
2019/11/28 职场文书