利用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 hashtable 修正版 下载
Dec 30 Javascript
js的toLowerCase方法用法实例
Jan 27 Javascript
JavaScript使用push方法添加一个元素到数组末尾用法实例
Apr 06 Javascript
jQuery Validate初步体验(一)
Dec 12 Javascript
JS实现图片延迟加载并淡入淡出效果的简单方法
Aug 25 Javascript
微信小程序 Image API实例详解
Sep 30 Javascript
工作中常用的js、jquery自定义扩展函数代码片段汇总
Dec 22 Javascript
五步轻松实现zTree的使用
Nov 01 Javascript
详解Vue.js中.native修饰符
Apr 24 Javascript
jquery多级树形下拉菜单的实例代码
Jul 09 jQuery
JS实现可视化音频效果的实例代码
Jan 16 Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
Jul 28 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
如何去掉文章里的 html 语法
2006/10/09 PHP
PHP用星号隐藏部份用户名、身份证、IP、手机号等实例
2014/04/08 PHP
php实现水印文字和缩略图的方法示例
2016/12/29 PHP
Jquery绑定事件(bind和live的区别介绍)
2013/08/23 Javascript
JS组件中bootstrap multiselect两大组件较量
2016/01/26 Javascript
非常漂亮的相册集 使用jquery制作相册集
2016/04/28 Javascript
jQuery验证插件validate使用详解
2016/05/11 Javascript
Vue仿手机qq的实例代码(demo)
2017/09/08 Javascript
基于js中document.cookie全面解析
2017/09/14 Javascript
jQuery实现html双向绑定功能示例
2017/10/09 jQuery
jQuery中可见性过滤器简单用法示例
2018/03/31 jQuery
微信小程序动态增加按钮组件
2018/09/14 Javascript
JavaScript设计模式之策略模式实现原理详解
2020/05/29 Javascript
vue自定义指令限制输入框输入值的步骤与完整代码
2020/08/30 Javascript
[02:33]2018 DOTA2亚洲邀请赛回顾视频 再次拾起那些美妙的时刻
2018/04/10 DOTA
python每隔N秒运行指定函数的方法
2015/03/16 Python
详解Python中使用base64模块来处理base64编码的方法
2016/07/01 Python
python 函数传参之传值还是传引用的分析
2017/09/07 Python
Windows 7下Python Web环境搭建图文教程
2018/03/20 Python
提升Python程序性能的7个习惯
2019/04/14 Python
django 多对多表的创建和插入代码实现
2019/09/09 Python
Python urlopen()和urlretrieve()用法解析
2020/01/07 Python
2020最新pycharm汉化安装(python工程狮亲测有效)
2020/04/26 Python
Python是怎样处理json模块的
2020/07/16 Python
Python包资源下载路径报404解决方案
2020/11/05 Python
仿酷狗html5手机音乐播放器主要部分代码
2013/05/15 HTML / CSS
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
Footshop罗马尼亚:最好的运动鞋选择
2019/09/10 全球购物
护理专科毕业推荐信
2013/11/10 职场文书
《桃林那间小木屋》教学反思
2014/05/01 职场文书
中职生求职信
2014/07/01 职场文书
2014年部门工作总结
2014/11/12 职场文书
2014年人事工作总结范文
2014/11/19 职场文书
2015年语文教研组工作总结
2015/05/23 职场文书
python unittest单元测试的步骤分析
2021/08/02 Python
《Estab Life》4月6日播出 正式PV、主视觉图公开
2022/03/20 日漫