plop工具的使用说明
plop是干嘛的?plop用于创建和实现项目脚手架和样板代码的命令行界面。
我们项目中的应用
快速构建模块化和结构化的目录以及常用样式和常用函数的生成。
如何使用plop快速构建一个模块
- 在终端输入如下命令
npm run plop
- 填写你要构建的模块的路经
需要注意的是,你所输入的路经不能是已经存在的
# 终端会有提示填写需要构建模块的路经
please input module path, like: 'demo/slb/plop-basepage' as 'src/views/demo/slb/plop-basepage'
# 比如我要构建的模块路经是 src/views/demo/slb/plop-basepage 那么久输入 demo/slb/plop-basepage 然后回车确认
demo/slb/plop-basepage
- 填写你标记,这个标记将会用于你构建的文件顶部,作为注释信息使用
# 终端会有提示填写你的名字,这将会用于新创建的文件的注释信息
please input yourname, it will be used in file tag
#文件顶部会生成类似这样的注释信息 src/views/demo/slb/plop-basepage/index.vue was created by 钵钵鸡 on 2024/7/17 16:23:07
钵钵鸡
截图如下展示:
生成的目录结构介绍
结构化界面介绍
<!-- src/views/demo/slb/plop-basepage/index.vue was created by 钵钵鸡 on 2024/7/17 16:51:15 -->
<script setup lang="ts">
import FilterLayout from "@/components/t-filter-layout/index";
import { serve } from "@/utils/oldutil";
import { formItems, options, usePlopModule } from "./construct";
import MyForm from "@/components/my-element-plus/my-form.vue";
import { sleep } from "@/utils/common";
const { components, filterLayoutHeight, mainHeight, tabsMapping, componentName, isComponent } = usePlopModule();
const globalData = reactive({
filterVal: {}//搜索区域的数据,响应式
});
//模拟请求,为select中的options赋值
const initOptions = async () => {
await sleep(2);
const opts = [
{ value: "1", label: "吃饭" },
{ value: "2", label: "睡觉" },
{ value: "3", label: "打豆豆" }
];
options.splice(0, options.length, ...opts);
};
//点击查询的事件
const subForm = async () => {
globalData.filterVal;
console.log("🚀 ~ subForm ~ globalData.filterVal:", globalData.filterVal);
if (componentName.value === "compA") {
const url = "";
const params = {};
const [res1] = await Promise.all([serve.get(url, params)]);
}
};
initOptions();
</script>
<template>
<FilterLayout @get-height="(h) => (filterLayoutHeight = h)">
<!-- ---------- Start:页签切换插槽 ---------- -->
<template #tabs>
<el-radio-group v-model="componentName">
<el-radio-button v-for="comp in Object.keys(components)" :key="comp" :label="comp">{{ tabsMapping[comp] }}</el-radio-button>
</el-radio-group>
</template>
<!-- ---------- End:页签切换插槽 ---------- -->
<!-- ---------- Start:页签切换插槽 ---------- -->
<template #form>
<MyForm v-model:form-data="globalData.filterVal" :form-items="formItems"></MyForm>
</template>
<!-- ---------- End:查询条件插槽 ---------- -->
<!-- ---------- Start:按钮插槽 ---------- -->
<template #button>
<el-button class="tml-3" type="primary" @click="subForm">查询</el-button>
</template>
<!-- ---------- End:按钮插槽 ---------- -->
</FilterLayout>
<KeepAlive>
<component :is="isComponent" :main-height="mainHeight" v-bind="globalData" />
</KeepAlive>
</template>
<style lang="scss" scoped></style>
控制层函数的介绍
// src/views/demo/slb/plop-basepage/construct/index.ts was created by 钵钵鸡 on 2024/7/17 16:51:15
import { useAppStore } from "@/store";
import { IObject } from "@/types/interface";
import { keys } from "lodash";
const widgets = import.meta.glob("../widgets/*.vue");
const config = {
//这里的key要与widgets下组件名称保持一致即可生效,value值就是tabs中使用的label
tabsMapping: {
compA: "我是界面1",
compB: "我是界面2"
}
};
//响应式的options
export const options = reactive<SelectOption[]>([]);
//定义搜索框区域的表单结构
export const formItems: FormItem[] = [
{
type: "input",
label: "姓名",
model: "name"
},
{
type: "select",
label: "性别",
model: "gender",
options: [
{ value: "1", label: "男" },
{ value: "2", label: "女" }
]
},
{
type: "select",
label: "爱好",
multiple: true,
model: "favorite",
options: options
},
{
type: "daterange",
label: "执行日期",
//时间区间选择需要传入两个key值来对接组件
model: ["startDate", "endDate"]
},
{
type: "datetimerange",
label: "执行时间",
//时间区间选择需要传入两个key值来对接组件
model: ["startTime", "endTime"]
}
];
export const usePlopModule = () => {
// 批量引入widgets下所有组件
const components = {};
keys(widgets).forEach((key) => {
const compName = key.match(/.*\/(.*).vue/)[1];
components[compName] = defineAsyncComponent(widgets[key]);
});
// 页面高度控制
const { state } = useAppStore();
const filterLayoutHeight = ref(56);
const mainHeight = computed(() => state.clientHeight - filterLayoutHeight.value);
//当前选中tab的value值,也是组件的名字
const componentName = ref(keys(config.tabsMapping)[0]);
//当前使用的tab组件
const isComponent = computed(() => components[componentName.value]);
return {
components: shallowRef<IObject>(components),
filterLayoutHeight,
mainHeight,
tabsMapping: config.tabsMapping,
componentName,
isComponent
};
};
tabs界面介绍
<!-- src/views/demo/slb/plop-basepage/widgets/compA.vue was created by 钵钵鸡 on 2024/7/17 16:51:15 -->
<script setup lang="ts">
import SectionLayout from "@/components/t-section-layout/index";
import { IObject } from "@/types/interface";
import { clientDefaultHeight } from "@/utils/oldutil";
interface Props {
mainHeight: number;
filterVal: IObject;
}
const props = defineProps<Props>();
const scrollHeight = computed(() => props.mainHeight - 56);
</script>
<template>
<SectionLayout hide-interval title="界面1标题">
<template #filter> <div class="download-excel !tright-0"></div></template>
<!-- 如果不需要固定view-style的高度可以删除view-style属性 -->
<el-scrollbar :view-style="`height:${clientDefaultHeight}px`" :height="scrollHeight"> </el-scrollbar>
</SectionLayout>
</template>
<style scoped lang="scss"></style>
其他
- 正常情况下,编写formItems即表单结构文件是会有ts校验的。比如,当你type="input"时,是不允许再有 options 属性的。
- 目前formItems只支持"input"、“select”、“daterange”、"datetimerange"四种类型的,后续会继续完善
- select类型下多选,返回的值和传入的值均为字符串,多个以逗号隔开。当传入required为true时,多选不能为空,所以在初始化的时候就要给默认值。
- daterange和datetimerange的mode类型为[string,string],前者是开始时间key键,后者是结束时间key键