plpo vue实战版教程

news2024/11/24 0:54:24

vue实战版教程

  • 什么是plpo
  • 安装
    • 1.将plop添加到您的项目
    • 2.全局安装plop(可选,但建议使用方便)
    • 3.在项目根目录下创建一个 plopfile.js
  • vue 实战(后台管理系统 - 增删改查)
    • 所需文件
    • 文件介绍
      • 创建配置文件 plopfile.js
      • 创建模板和脚本命令文件
        • 模板创建逻辑
        • 根据自己的需求创建view模板文件
          • view --list 文件夹
          • view --detail/drawer文件夹
          • view --detail/modal文件夹 同理(不做描述了)
    • 运行创建项目
      • 效果展示

什么是plpo

它是一个命令行工具,专门用于构建生成器,这些生成器可以帮助开发者快速生成代码模板,特别是对于大型的后台管理系统,页面很多相似的内容,重复率很高的项目,我们可以设立一个模板(列表、详情、路由等)(vue、js、css文件等’),一次构建重复创建。

安装

1.将plop添加到您的项目

 npm install --save-dev plop
  • ps: 如果你没有全局安装plop,你需要在设置一个 npm 脚本命令来为你运行polp:
//package.json
{
	...,
	"scripts":{
		"plop":"plop"
	},
	...
}

2.全局安装plop(可选,但建议使用方便)

npm install -g plop

3.在项目根目录下创建一个 plopfile.js

创建一个基本的生成器

// plop 的入口文件 plopfile.js
// 需要导出一个函数,函数接收一个plop对象,用于创建生成器任务
module.exports = plop => {
  // setGenerator可以设置一个生成器,每个生成器都可用于生成特定的文件
  // 接收两个参数,生成器的名称和配置选项
  plop.setGenerator('component', {
    // 生成器的描述
    description: 'create a component',
    
    // 发起命令行询问(将来生成器工作时发起的询问,它是一个数组,每个对象都是一次询问)
    prompts: [{
      // 类型
      type: 'input',
      // 接收变量的参数
      name: 'name',
      // 询问提示信息
      message: 'component name',
      // 默认值
      default: 'MyComponent'
    }],
    
    // 完成命令行后执行的操作,每个对象都是动作对象
    actions: [{
      // 动作类型
      type: 'add',
      // 生成文件的输出路径
      path: 'src/views/${name}/list/index.vue',
      // template 模板的文件路径,目录下的文件遵循hbs的语法规则
      templateFile: 'plopTemplate/view/list/index.vue'
    }]
  })
}


  • actions 之 path
path中的{{name}}是一种变量书写形式,它对应的就是prompts对象数组中的name接收的值
假如 name='Test1',那这里的path就相当于src/views/Test1/list/index.vue
  • actions 之 templateFile

templateFile 就是该文件的模板文件路径
在这里插入图片描述
我们在模板中同样可以使用{{变量名称}},的方式来传入我们在prompts中接收的变量

在这里插入图片描述
多个动作
同样的,如果我们希望生成多个文件,就可以配置多个动作对象和对应的模板即可即可,如

  actions: [{
    type: "add",
    path: `src/views/${name}/list/index.vue`,
    templateFile: "plopTemplate/view/list/index.vue",
  }, {
    type: "add",
    path: `src/views/${name}/detail/index.vue`,
    templateFile: "plopTemplate/view/detail/index.vue",
  }]

vue 实战(后台管理系统 - 增删改查)

所需文件

在这里插入图片描述

文件介绍

在项目跟目录下,创建配置文件 plopfile.js,内容如下:

创建配置文件 plopfile.js

const viewGenerator = require("./plopTemplate/prompt");
module.exports = (plop) => {
  plop.setGenerator("create", viewGenerator);
};

plopfile.js 中导出一个函数,该函数接受 plop 对象作为它的第一个参数;
plop 对象公开包含 setGenerator(name, config)函数的 plop api 对象。

创建模板和脚本命令文件

在项目根目录下新建文件夹(如plopTemplates),放置模板(view/list view/detail文件)和脚本命令(prompt.js)文件

模板创建逻辑

prompt.js脚本命名如下,提示语和创建动作
1.手动输入页面名称
2.是否添加增改组件
3.选择是(选择添加抽屉or弹窗)
4.是否添加路由

module.exports = {
  description: "新建一个模块",
  prompts: [
    {
      type: "input",
      name: "name",
      message: "页面名称:",
      validate(name) {
        if (!name) {
          return "请输入页面名称";
        }
        return true;
      },
    },
    {
      type: "confirm",
      name: "hasDetail",
      message: "你想要给新页面添加详情组件(抽屉/弹窗)吗?",
    },
    {
      type: "confirm",
      name: "hasDrawer",
      message: "你想要给模块添加详情抽屉吗?",
      when: function (answer) {
        // 当hasDetail为true的时候才会到达这步
        return answer.hasDetail; // 只有我return true才会这个confirm
      },
    },
    {
      type: "confirm",
      name: "hasModal",
      message: "你想要给模块添加详情弹窗吗?",
      when: function (answer) {
        return !answer.hasDrawer && answer.hasDetail;
      },
    },
    {
      type: "confirm",
      name: "hasRoute",
      message: "你想要给模块增加路由吗?(在route下创建为name的路径)",
    },
  ],
  actions: (data) => {
    const { hasDrawer, hasModal, hasRoute, name } = data;
    let listActions = [];
    const baseActions = [
      {
        type: "add",
        path: `src/views/${name}/list/index.vue`,
        templateFile: "plopTemplate/view/list/index.vue",
      },
      {
        type: "add",
        path: `src/views/${name}/list/index.less`,
        templateFile: "plopTemplate/view/list/index.less",
      },
      {
        type: "add",
        path: `src/views/${name}/list/columns.js`,
        templateFile: "plopTemplate/view/list/columns.js",
      },
    ];
    listActions = listActions.concat(baseActions);
    const drawerActions = [
      {
        type: "add",
        path: `src/views/${name}/detail/drawer/index.vue`,
        templateFile: "plopTemplate/view/detail/drawer/index.vue",
      },
      {
        type: "add",
        path: `src/views/${name}/detail/drawer/index.less`,
        templateFile: "plopTemplate/view/detail/drawer/index.less",
      },
    ];
    const modalActions = [
      {
        type: "add",
        path: `src/views/${name}/detail/modal/index.vue`,
        templateFile: "plopTemplate/view/detail/modal/index.vue",
      },
      {
        type: "add",
        path: `src/views/${name}/detail/modal/index.less`,
        templateFile: "plopTemplate/view/detail/modal/index.less",
      },
    ];
    const routeAction = [
      {
        type: "add",
        path: `src/router/routes/${name}.js`,
        templateFile: "plopTemplate/route/index.js",
      },
    ];
    if (hasDrawer) {
      listActions = listActions.concat(drawerActions);
    }
    if (hasModal) {
      listActions = listActions.concat(modalActions);
    }
    if (hasRoute) {
      listActions = listActions.concat(routeAction);
    }
    return listActions;
  },
};
根据自己的需求创建view模板文件

下面只做于逻辑参考

view --list 文件夹
  • index.vue
<!-- eslint-disable -->
<template>
  <div class="{{name}}Container">
    <div
      style="padding: 10px 0"
      class="search"
    >
      <div class="search_form">
        <a-input
          style="width: 200px"
          placeholder="请输入用户名"
          suffix-icon="el-icon-search"
          v-model="query.username"
        ></a-input>
      </div>
      <div class="search_btns">
        <a-button
          class="btn"
          type="primary"
          @click="getList(query)"
          >搜索</a-button
        >
        <a-button
          class="btn"
          type="warning"
          @click="getList"
          >重置</a-button
        >
      </div>
    </div>
    <div class="btns">
      {{#if hasDetail}}
      <a-button
        @click="handleAdd"
        class="float-left"
        type="primary"
        >新增</a-button
      >
      {{/if}}
      <div class="btns_right">
        <a-button
          type="primary"
          @click="handleImport"
          >导入</a-button
        >
        <a-button
          type="primary"
          @click="handleExport"
          >导出</a-button
        >
      </div>
    </div>
    <a-table
      bordered
      :data-source="dataSource"
      :columns="columns"
    >
      <template
        slot="action"
        slot-scope="text, record"
      >
        {{#if hasDetail}}
        <a @click="handleDetail(record)">编辑</a>
        {{/if}}
        <a
          style="color: red; margin-left: 10px"
          @click="handleDel(record)"
          >删除</a
        >
      </template>
    </a-table>
    {{#if hasModal}}
    <modal-com
      v-model="detailVisible"
      :detailData="detailData"
    ></modal-com>
    {{/if}}
    {{#if hasDrawer}}
    <drawer-com
      v-model="detailVisible"
      :detailData="detailData"
    ></drawer-com>
    {{/if}}
  </div>
</template>
<script>
import getColumns from "./columns";
{{#if hasDrawer}}
import drawerCom from "../detail/drawer/index.vue";
{{/if}}
{{#if hasModal}}
import modalCom from "../detail/modal/index.vue";
{{/if}}
export default {
  name:"{{name}}",
  components: {
    {{#if hasDrawer}}
    drawerCom,
    {{/if}}
    {{#if hasModal}}
    modalCom,
    {{/if}}
  },
  data() {
    return{
      columns: getColumns.call(this),
      dataSource: [
        { id:1,name: "李荣浩", age: 18, sex: "男" },
        { id:2,name: "李菲儿", age: 20, sex: "女" },
        { id:3,name: "李小龙", age: 26, sex: "男" },
      ],
      detailVisible: false,
      detailData: {},
      query:{username:''}
    }
  },
  mounted() {
    this.getList();
  },
  methods: {
    // 请求数据
    getList(query={}){
      //请求逻辑
    },
     // 导入
     handleImport() {},
    // 导出
    handleExport() {},
    // 跳转添加
    handleAdd() {
      this.detailVisible = true;
      this.detailData={}
    },
    // 跳转详情
    handleDetail(record) {
      this.detailVisible = true;
      this.detailData=record
    },
    // 删除
    handleDel(record) {
      this.$confirm({
        title: "系统提示",
        content: "确定要删除该条数据吗",
        onOk: async () => {
          try {
             //删除逻辑
          } catch (e) {
            console.log(e);
          }
        },
      });
    },
  },
}
</script>
<style lang="less">
@import "./index.less";
</style>

  • columns.js
const getColumns = function () {
  return [
    {
      title: "序号",
      dataIndex: "index",
      customRender: (text, record, index) => index + 1,
      fixed: "left",
    },
    {
      title: "姓名",
      dataIndex: "name",
    },
    {
      title: "年龄",
      dataIndex: "age",
    },
    {
      title: "性别",
      dataIndex: "sex",
    },

    {
      title: "操作",
      width: 120,
      scopedSlots: {
        customRender: "action",
      },
      fixed: "right",
    },
  ];
};

export default getColumns;

  • index.less
.{{name}}Container {
  margin: 10px;
  .search {
    float: left;
    &_form {
      float: left;
    }
    &_btns {
      float: left;
      .ant-btn {
        margin-left: 10px;
      }
    }
  }
  .btns {
    height: 60px;
    display: flex;
    width: 100%;
    justify-content: space-between;
    position: relative;
    &_right {
      position: absolute;
      right: 0;
    }
    .ant-btn {
      margin: 10px 10px 10px 0px;
    }
  }
}

view --detail/drawer文件夹
  • index.vue
<template>
  <a-drawer
    width="500"
    placement="right"
    :visible="visible"
    @close="handleCancel"
    :z-index="2024"
    :title="title"
  >
    <div class="{{name}}Detail">
      <a-form
        :form="form"
        class="fields"
      >
        <a-form-item
          label="姓名"
          class="fields-item"
        >
          <a-input
            v-decorator="['name', { rules: [{ required: true, message: '请填写姓名!' }] }]"
          />
        </a-form-item>
        <a-form-item
          label="年龄"
          class="fields-item"
        >
          <a-input v-decorator="['age', { rules: [{ required: true, message: '请填写年龄!' }] }]" />
        </a-form-item>
        <a-form-item
          label="性别"
          class="fields-item"
        >
          <a-radio-group
            v-decorator="['sex', { rules: [{ required: true, message: '请选择性别!' }] }]"
          >
            <a-radio value="男"></a-radio>
            <a-radio value="女"></a-radio>
          </a-radio-group>
        </a-form-item>
      </a-form>
    </div>
    <div class="button-wrap">
      <a-button
        type="plain"
        class="mg-r_2"
        @click="handleCancel"
        >取消</a-button
      >
      <a-button
        type="primary"
        :loading="loading"
        @click="onSave"
        >保存</a-button
      >
    </div>
  </a-drawer>
</template>

<script>
export default {
  name: "{{name}}Detail",
  props: {
    value: {
      type: Boolean,
      default: false,
    },
    detailData: {
      type: Object,
      default: () => {},
    },
  },
  model: {
    prop: "value",
    event: "change",
  },
  computed: {
    visible: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit("change", val);
      },
    },
    title() {
      return this.detailData?.id ? "编辑" : "新增";
    },
  },
  watch: {
    visible(newVal) {
      if (newVal) {
        if (this.detailData.id) {
          const { age, sex, name } = this.detailData;
          this.$nextTick(() => {
            this.form.setFieldsValue({
              age,
              sex,
              name,
            });
          });
        } else {
          this.form.resetFields();
        }
      }
    },
  },
  data() {
    return {
      loading: false,
      form: this.$form.createForm(this),
    };
  },

  methods: {
    handleCancel() {
      this.$emit("change", false);
    },
    onSave() {
      this.form.validateFields(async (err, values) => {
        if (!err) {
          // 保存逻辑
        }
      });
    },
  },
};
</script>

<style lang="less">
@import "./index.less";
</style>

  • index.less
.{{name}}Detail{
  position: relative;
  .fields {
    &-item {
      display: flex;
      width: 100%;
      .ant-form-item-control-wrapper {
        flex: 1;
      }
    }
  }

}
.button-wrap {
  width: calc(100% - 60px);
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  bottom: 20px;
}
view --detail/modal文件夹 同理(不做描述了)

运行创建项目

pnpm run plop view

在这里插入图片描述

效果展示

在这里插入图片描述

  • 抽屉详情
    在这里插入图片描述

在这里插入图片描述

  • 弹窗详情
    在这里插入图片描述

在这里插入图片描述

  • 无详情
    在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2208272.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Emu3:北京智源推出AI多模态世界模型,超越DeepMind和微软,刷新了8项性能指标

Emu3是北京智源人工智能研究院推出的一款原生多模态世界模型&#xff0c;采用智源自研的多模态自回归技术路径&#xff0c;在图像、视频、文字上联合训练&#xff0c;使模型具备原生多模态能力&#xff0c;实现图像、视频、文字的统一输入和输出。Emu3将各种内容转换为离散符号…

食堂校园预约就餐系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;商品管理&#xff0c;论坛管理&#xff0c;用户管理&#xff0c;商家管理&#xff0c;公告信息管理&#xff0c;基础数据管理 微信端账号功能包括&#xff1a;系统首页&#xf…

【Flutter、H5、Web?前端个人总结】分享从业经历经验、自我规范准则,纯干货

前言 hi&#xff0c;正式接触web前端已经经过了两年的时间&#xff0c;从大学的java后端转型到web前端&#xff0c;再到后续转战Flutter&#xff0c;逐渐对前端有了一些心得体会&#xff0c;其实在当下前端的呈现形式一直在变化&#xff0c;无论你是用原生、还是web还是混编的…

vulnhub-Kioptrix_Level_1靶机的测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、解决检测不到IP的问题 2、信息搜集 3、利用exp ①mod_ssl2.8版本漏洞 ②smb2.2版本漏洞 四、结论 一、测试环境 1、系统环境 渗透机&#xff1a;kali2021.1(192.168.202.134) 靶 机…

【前端构建】Webpack: 现代前端开发的核心工具

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Webpack: 现代前端开发的核心工具1. 引言2. Webpack 的核心概念2.1 入口&#x…

vmware下ubuntu18.04中使用笔记本的摄像头

步骤1&#xff1a;在windows中检查相机状态 win10系统中&#xff0c;在左下的搜索栏&#xff0c;搜索“相机”&#xff0c;点击进入即可打开相机&#xff0c;并正常显示图像。 注意&#xff1a;如果相机连接到了虚拟机&#xff0c;则不能显示正常。 步骤2&#xff1a;…

解决ubuntu 下 VS code 无法打开点击没反应问题

从Ubuntu 22.04 升级到ubuntu 24.04 后&#xff0c;发现Vsode无法打开&#xff0c;不论是点击图标&#xff0c;还是terminator里面运行code 可执行程序&#xff0c;均没有反应。debug如下: 提示权限不够。 解决方案&#xff1a; sudo sysctl -w kernel.apparmor_restrict_unp…

最佳BD仓储物流方案选择秘诀!

BD仓储部署策略的执行方案是一项既精细又全面的流程&#xff0c;目的在于保障BD装备的安全保管、高效化管理以及迅速调动。以下详列了一项涵盖众多核心环节及要素的具体执行方案&#xff1a; 一、项目开展与策划 确立项目核心目标&#xff1a;精准定位BD仓储解决方案的关键目…

瑞芯微RK3399开发板Android7.1修改网络优先级方法,触觉智能演示

本文介绍Android7.1修改网络优先级方法&#xff0c;基于触觉智能SBC3968主板&#xff0c;搭载瑞芯微RK3399芯片&#xff0c;这块主板的网络优先级默认是网口&#xff1e;WiFi&#xff1e;4G&#xff0c;下面就手把手教大家怎么修改。 1、查看当前网络优先级数值 源码根目录下执…

springboot乐享田园系统

基于springbootvue实现的乐享田园系统 &#xff08;源码L文ppt&#xff09;4-080 4.3 系统结构设计 构图是系统的体系结构&#xff0c;体系结构是体系结构体系的重要组成部分。系统的总体结构设计如图4-2所示。 图4-2 系统总体架构图 4.4 数据库设计 4.4.1 数据…

IDEA使用Alibaba Cloud Toolkit插件自动化部署jar包

一、下载插件 二、添加服务器主机 三、填写自己服务器配置 四、添加配置 五、配置说明 六、选择maven打包模块 七、maven打包后的jar包位置配一下 八、点击运行发现成功

MySQL-数据库的基础操作 o(´^`)o

文本目录&#xff1a; ❄️一、数据库操作&#xff1a; ☑ 1、查看所有的数据库&#xff1a; ☑ 2、创建数据库&#xff1a; ☑ 3、使用数据库&#xff1a; ☑ 4、删除数据库&#xff1a; ❄️二、常用的数据类型&#xff1a; ➷ 1、数值类型&#xff1a; ➷ 2、字符串类型&a…

MacOS安装MySQL和Navicat

MacOS安装MySQL和Navicat 前言一、MySQL1、下载并安装 MySQL2、启动 MySQL 并连接3、创建数据库 二、Navicat1、官网下载2、安装3、配置链接 叮嘟&#xff01;这里是小啊呜的学习课程资料整理。好记性不如烂笔头&#xff0c;今天也是努力进步的一天。一起加油进阶吧&#xff01…

(JAVA)B树和B+树的实现原理阐述

1. B 树 2-3树中&#xff0c;一个节点最多能有两个key&#xff0c;它的实现红黑树中适用对链接染色的方式去表达这两个key。下面将学习另一种树形结构B树&#xff0c;这种数据结构中&#xff0c;一个节点允许多余两个key的存在。 B树是一种树状数据结构&#xff0c;它能够存储…

Hopfield神经网络求解旅行商问题(Traveling Salesman Problem,TSP),提供完整MATLAB代码,复制粘贴即可运行

Hopfield神经网络是以美国物理学家约翰霍普菲尔德&#xff08;John Hopfield&#xff09;的名字命名的。他在1982年提出了这种类型的神经网络模型&#xff0c;因此通常被称为Hopfield网络。Hopfield网络是一种早期的人工神经网络&#xff0c;具有以下特点&#xff1a; 递归连接…

【重磅升级】基于大数据的股票量化分析与预测系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 伴随全球经济一体化和我国经济的快速发展&#xff0c;中国股票市场对世界经济的影响力不断攀升&#xff0c;中国股市已成为全球第二大股票交易市场。在当今的金融市场中&#xff0c;股票价格的波动…

图像处理中常用的统计矩

目录 原点矩中心矩常用的统计矩偏度&#xff08;Skewness&#xff09;定义解释 峰度&#xff08;Kurtosis&#xff09;定义解释 统计矩的应用MATLAB相关函数 原点矩&#xff08;Moment about the Origin&#xff09;和中心矩&#xff08;Central Moment&#xff09;是概率论和数…

YOLOv11改进 | 融合篇,YOLOv11改进主干网络为MobileNetV3+CA注意机制

YOLOv11改进介绍 YOLOv11 跟 YOLOv8 结构差不多相似,只是作者在 YOLOv8 基础上进行了改进,我感觉 YOLOv11 训练速度更快,map和精度应该比 YOLOv8 高一些,所以我会把 YOLOv11 改进也写在本专栏里面。YOLOv11 改进,可以看往期 YOLOv8 改进主干网络教程,原理都是一样的,这…

【m6A】如何调节【免疫】,双热点如何碰撞出火花?

国自然已经放榜许久&#xff0c;【免疫】和【m6A】&#xff08;N6-甲基腺苷&#xff09;再次成为热门研究主题。m6A作为真核生物mRNA的主要表观遗传修饰之一&#xff0c;它通过调控mRNA的稳定性、剪接、运输和翻译等过程&#xff0c;进而影响基因的表达[1]。 图1.关键词【免疫、…

热烈祝贺!开利网络成为第一批广州市数据要素入库企业

今日&#xff0c;我们怀着无比激动的心情&#xff0c;热烈祝贺 广州市开利网络科技有限公司成为第一批广州市数据要素入库企业&#xff01;这一殊荣&#xff0c;是对 广州市开利网络科技有限公司在数据领域卓越表现的高度认可&#xff0c;更是 广州市开利网络科技有限公司发展历…