vue3使用plop模板指令生成页面

1、vue-cli新建一个vue3项目

vue-cli需要3.0版本,可以使用vue -V查看版本,node需要16版本及以上(node:v16.20.2,npm:8.19.4
,vue-cli: 5.0.8)

新建一个名为test3-vue的vue3的项目

vue create test1-vue3

新建成功后进入项目文件夹

cd test1-vue3

2、安装plop

根据第一步新建项目的时候选的yarn或者npm,来使用相应的指令安装(版本:^4.0.0)

 // yarn
yarn add plop --dev
// npm
npm install plop 

3、安装其他插件(inquirer-file-path、read-metadata)

// inquirer-file-path插件可以使用指令选择文件名称(版本:^1.0.1)
npm install --save inquirer-file-path
// read-metadata根据地址获取json文件的内容(版本:^1.0.0)
npm install read-metadata

vue2项目可以使用inquirer-parse-json-file插件替代这两个插件

这两个插件的目的是在指令中选择配置文件并把配置文件中的内容与命令行的内容合并保存在配置项中,配置文件:plop_template/config,主要是存放每个页面不同的数据内容,比如列表页中的查询参数、table中的显示项、接口名称等信息。

4、在package.json中配置启动plop指令

在scripts中加入:“plop”: “plop”

在这里插入图片描述
5、新建一个plop_template文件夹

目录:
在这里插入图片描述

config:json文件,每个页面具体数据的配置文件
default.json内容:

{
  "model":[{ 
    "prop":"title",
    "label":"标题"
  },{
    "prop":"sub_title",
    "label":"子标题"
  },{
    "prop":"type_id",
    "label":"类型"
  },{
    "prop":"enabled",
    "label":"启用",
    "type":"Boolean"
  },{
    "prop":"remark",
    "label":"备注",
    "type":"textarea",
    "mode":["form"],
    "placeholder":"占位内容",
    "default":"这是备注"

  }],
  "api":{
    "list": "/2685-11",
    "view": "/2685-21",
    "add": "/2685-2",
    "edit": "/2685-3",
    "del": "/2685-3"
  },
  "query":[{
    "prop":"title",
    "placehold":"搜索占位"
  }]
}

script:一些模板中需要用到的助手代码方法

module.exports = function (plop) {
  plop.setHelper('ifcode', function (listitem, opts) {
    if (!listitem.mode || listitem.mode.find(item => item === 'table')) { // 是否显示
      if (listitem.isview) { // 有详情页点击链接列
        return opts.fn(this)
      } else {
        return opts.inverse(this)
      }
    } else {
      return ''
    }
  })
  plop.setHelper('difcode', function (val, opts) {
    if (!val || val.find(item => item === 'form')) {
      return opts.fn(this)
    } else {
      return opts.inverse(this)
    }
  })
  plop.setHelper('modetype', function (val, opts) {
    let result = ''
    switch (val.type) {
      case 'select':
        result = '<el-select v-model="listdetail.' + val.prop + '" :disabled="editdisable" placeholder="' + val.placeholder + '" class="w-full mr-3">' +
          '<el-option label="选项" value="1" /></el-select>'
        break
      case 'textarea':
        result = '<el-input v-model="listdetail.' + val.prop + '" :disabled="editdisable" type="textarea" placeholder="' + val.placeholder + '" />'
        break
      case 'number':
        result = '<el-input v-model="listdetail.' + val.prop + '" :disabled="editdisable" type="number" placeholder="' + val.placeholder + '" />'
        break
      default:
        result = '<el-input v-model="listdetail.' + val.prop + '" :disabled="editdisable" placeholder="' + val.placeholder + '" />'
        break
    }
    return result
  })
  plop.setHelper('eachIndex', function (context, options) {
    let ret = ''
    for (let i = 0, j = context.length; i < j; i++) {
      ret = ret + options.fn({ it: context[i], isLast: i == context.length - 1 })
    }
    return ret
  })
  plop.setHelper('rulesIndex', function (context, options) {
    let ret = ''
    const newliat = []
    for (let i = 0, j = context.length; i < j; i++) {
      if (context[i].isrequired) {
        newliat.push(context[i])
      }
    }
    for (let ii = 0, j = newliat.length; ii < j; ii++) {
      ret = ret + options.fn({ it: newliat[ii], isLast: ii == newliat.length - 1 })
    }
    return ret
  })
}

template:生成页面所需的模板 ,detail.hbs:详情页面,list.hbs列表页面

detail.hbs页面内容:

<template>
  <div>
    <el-drawer
      :title="!listdetail?'添加数据':'修改数据'"
      :modal="false"
      size="30%"
      custom-class="absolute"
      :modal-append-to-body="false"
      :append-to-body="false"
      :wrapper-closable="false"
      :visible.sync="drawershow"
      direction="rtl"
      :before-close="handleClose"
    >
      <div class="pl-5 pr-5">
        <el-form ref="form" label-position="right" label-width="80px" :model="form" :rules="rules">
          {{#each config.model}}
          {{#difcode mode}}
          <el-form-item label="{{label}}"{{#if isrequired}} prop="{{prop}}"{{/if}}>
            {{#modetype this}}{{/modetype}}
          </el-form-item>
          {{/difcode}}
          {{/each}}
          <el-form-item class="text-center">
            <el-button v-if="editdisable" type="primary" @click="formdisable = false">
              <span>修改</span>
            </el-button>
            <el-button v-if="!editdisable" type="primary" @click="drawersubmit('form')">
              <span>\{{ !listdetail?'确认添加':'确认修改' }}</span>
            </el-button>
            <el-button @click="handleClose">
              取消
            </el-button>
          </el-form-item>
        </el-form>
      </div>
    </el-drawer>
  </div>
</template>
<script>
  import { clone } from 'lodash'
export default {
  props: {
    listdetail: {
      type: [Object, Boolean]
    },
    drawershow: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      form: {},
      formdisable: true,
      rules: {
      {{#rulesIndex config.model}}
      {{#if it.isrequired}}
        {{it.prop}}: [
          { required: true, trigger: 'blur', message: '请输入{{it.label}}' }
        ]{{#if isLast}}{{else}},{{/if}}
      {{/if}}
      {{/rulesIndex}}
      }
    }
  },
  computed: {
    editdisable: {
      get () {
        return this.listdetail && this.formdisable
      },
      set (val) {}
    }
  },
  watch: {
    listdetail: {
      handler (cval, oval) { // 监听传入的数据变化(type没变的时候如果改变传参没有办法重新计算editdisable)
        this.initForm(cval)
        if (oval._id !== cval._id) { // 如果数据改变需要重新设置editdisable为true,输入框修改为不可输入状态
          this.formdisable = true
        }
        if (this.$refs.form) {
          this.$refs.form.resetFields()
        }
      }
    },
    drawershow: { // 可能parent有变化,需要做initForm
      handler (cval, oval) {
        if (!cval) {
          this.initForm(false)
        }
      }
    }
  },
  methods: {
    initForm (obj) {
      if (this.$refs.form) {
        this.$refs.form.resetFields()
      }
      this.editdisable = !!obj
      if (obj) {
        console.log(obj)
        this.form = clone(this.listdetail)
      } else {
        this.form = {}
      }
    },
    drawersubmit (formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.$emit('submit', this.form)
        }
      })
    },
    handleClose () {
      this.$emit('close')
    }
  }
}
</script>
<style scoped>
</style>

5、配置plopfile.js文件

const helpler = require('./plop_template/script/helper') // 引入助手文件
const inquirerDirectory = require('inquirer-file-path') // 选择文件
const read = require('read-metadata'); // 从json中读取json数据

module.exports = function (plop) {
  helpler(plop)
  plop.setPrompt('directory', inquirerDirectory)
  plop.setGenerator('page', { // 这里的 test 是一个自己设定的名字,在执行命令行的时候会用到
    description: '分页增删查改', // 这里是对这个plop的功能描述
    prompts: [
      {
        type: 'confirm', // 问题的类型
        name: 'haspagelist', // 问题对应得到答案的变量名,可以在actions中使用该变量
        message: '是否需要分页:', // 在命令行中的问题
        default: true // 问题的默认答案
      },
      {
        type: 'input', // 问题的类型
        name: 'filePath', // 问题对应得到答案的变量名,可以在actions中使用该变量
        message: '在page目录下生成文件:', // 在命令行中的问题
        suffix: 'pages/',
        default: 'index.vue' // 问题的默认答案
      },
      {
        type: 'confirm', // 问题的类型
        name: 'hasDetail', // 问题对应得到答案的变量名,可以在actions中使用该变量
        message: '是否需要详情抽屉:', // 在命令行中的问题
        default: true // 问题的默认答案
      },
      {
        type: 'directory', // 问题的类型
        name: 'config', // 问题对应得到答案的变量名,可以在actions中使用该变量
        message: '选择配置文件', // 在命令行中的问题
        basePath: 'plop_template/config',
        default: {}, // 问题的默认答案
      }
    ],
    actions: (data) => {
      read(`plop_template/config/${data.config}`, function(err, res){
        // 因为inquirer-parse-json-file插件不兼容,没有找到合适的插件,所以只好获取文件名称,再手动去获取文件内容
        data.config = res
      });
      const path = `pages/${data.filePath}`
      const folder = path.substring(0, path.lastIndexOf('/'))
      const actions = [
        {
          type: 'add', // 操作类型,这里是添加文件
          path, // 模板生成的路径
          templateFile: 'plop_template/template/page/list.hbs', // 模板的路径
          data
        }
      ]
      if (data.hasDetail) {
        actions.push({
          type: 'add', // 操作类型,这里是添加文件
          path: `${folder}/-detail.vue`, // 模板生成的路径
          templateFile: 'plop_template/template/page/-detail.hbs', // 模板的路径
          data
        })
      }
      return actions
    }
  })
}

6、运行plop

npm run plop

根据提示问题进行选择
在这里插入图片描述
最终生成的文件目录
在这里插入图片描述
生成的detail.vue的文件内容

<template>
  <div>
    <el-drawer
      :title="!listdetail?'添加数据':'修改数据'"
      :modal="false"
      size="30%"
      custom-class="absolute"
      :modal-append-to-body="false"
      :append-to-body="false"
      :wrapper-closable="false"
      :visible.sync="drawershow"
      direction="rtl"
      :before-close="handleClose"
    >
      <div class="pl-5 pr-5">
        <el-form ref="form" label-position="right" label-width="80px" :model="form" :rules="rules">
          <el-form-item label="标题">
            <el-input v-model="listdetail.title" :disabled="editdisable" placeholder="undefined" />
          </el-form-item>
          <el-form-item label="子标题">
            <el-input v-model="listdetail.sub_title" :disabled="editdisable" placeholder="undefined" />
          </el-form-item>
          <el-form-item label="类型">
            <el-input v-model="listdetail.type_id" :disabled="editdisable" placeholder="undefined" />
          </el-form-item>
          <el-form-item label="启用">
            <el-input v-model="listdetail.enabled" :disabled="editdisable" placeholder="undefined" />
          </el-form-item>
          <el-form-item label="备注">
            <el-input v-model="listdetail.remark" :disabled="editdisable" type="textarea" placeholder="占位内容" />
          </el-form-item>
          <el-form-item class="text-center">
            <el-button v-if="editdisable" type="primary" @click="formdisable = false">
              <span>修改</span>
            </el-button>
            <el-button v-if="!editdisable" type="primary" @click="drawersubmit('form')">
              <span>{{ !listdetail?'确认添加':'确认修改' }}</span>
            </el-button>
            <el-button @click="handleClose">
              取消
            </el-button>
          </el-form-item>
        </el-form>
      </div>
    </el-drawer>
  </div>
</template>
<script>
  import { clone } from 'lodash'
export default {
  props: {
    listdetail: {
      type: [Object, Boolean]
    },
    drawershow: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      form: {},
      formdisable: true,
      rules: {
      }
    }
  },
  computed: {
    editdisable: {
      get () {
        return this.listdetail && this.formdisable
      },
      set (val) {}
    }
  },
  watch: {
    listdetail: {
      handler (cval, oval) { // 监听传入的数据变化(type没变的时候如果改变传参没有办法重新计算editdisable)
        this.initForm(cval)
        if (oval._id !== cval._id) { // 如果数据改变需要重新设置editdisable为true,输入框修改为不可输入状态
          this.formdisable = true
        }
        if (this.$refs.form) {
          this.$refs.form.resetFields()
        }
      }
    },
    drawershow: { // 可能parent有变化,需要做initForm
      handler (cval, oval) {
        if (!cval) {
          this.initForm(false)
        }
      }
    }
  },
  methods: {
    initForm (obj) {
      if (this.$refs.form) {
        this.$refs.form.resetFields()
      }
      this.editdisable = !!obj
      if (obj) {
        console.log(obj)
        this.form = clone(this.listdetail)
      } else {
        this.form = {}
      }
    },
    drawersubmit (formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.$emit('submit', this.form)
        }
      })
    },
    handleClose () {
      this.$emit('close')
    }
  }
}
</script>
<style scoped>
</style>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3是前端开发中常用的一种JavaScript框架,用于构建用户界面。登录页面模板是一种用于展示登录页面的可重用组件,可以在Vue3中使用。 在Vue3中,我们可以使用Vue CLI(Vue命令行界面)来快速创建一个Vue项目。安装好Vue CLI后,可以运行以下命令创建一个新项目: ``` vue create login-template ``` 然后进入项目目录: ``` cd login-template ``` 在项目中,我们可以创建一个新的组件来表示登录页面。在src目录下创建一个Login.vue文件,然后在这个文件中编写登录页面的HTML和CSS代码,如下所示: ```vue <template> <div class="login"> <h1>Login Page</h1> <form> <label for="username">Username:</label> <input type="text" id="username" v-model="username"> <label for="password">Password:</label> <input type="password" id="password" v-model="password"> <button @click="login">Login</button> </form> </div> </template> <script> export default { data() { return { username: '', password: '' } }, methods: { login() { // 在这里处理登录逻辑,比如发送登录请求到后端API // 根据返回结果决定是否跳转到其他页面或显示错误信息 } } } </script> <style scoped> .login { display: flex; flex-direction: column; align-items: center; margin-top: 100px; } h1 { margin-bottom: 20px; } label { margin-bottom: 10px; } input { margin-bottom: 20px; } button { padding: 10px 20px; } </style> ``` 在这个组件中,我们使用Vue的单文件组件语法。其中,`template`部分包含了登录页面的HTML结构,`script`部分包含了与登录相关的数据和方法,`style`部分包含了登录页面的样式。 然后,在App.vue中引入并使用登录页面组件,在src目录下的App.vue文件中添加以下代码: ```vue <template> <div id="app"> <Login /> </div> </template> <script> import Login from './Login.vue' export default { name: 'App', components: { Login } } </script> <style> #app { font-family: Arial, Helvetica, sans-serif; } </style> ``` 最后,在main.js文件中创建Vue实例,并将App组件渲染到页面中,如下所示: ```javascript import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app') ``` 至此,我们完成了一个简单的Vue3登录页面模板。在浏览器中运行项目,就可以看到一个基本的登录页面,包含用户名、密码输入框和登录按钮。用户在输入用户名和密码后,可以点击登录按钮触发登录方法。你可以根据自己的需求进一步完善登录逻辑,比如校验用户名密码、跳转到其他页面等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值