赞
踩
vue3已经出来2年了,但是在实际工作中却很少用到,很多前端的同事也在跃跃欲试在工作中使用vue3,作为相对保守派的我是不敢轻易尝试的,但是技术的革新是时代发展的需要,我们闭上双眼无视时代的进步,那么进步就不存在了吗?所以唯心主义是不成立的,是早晚要被淘汰的。基于不被淘汰的目的我也大胆的尝试了一把vue3的开发模式。当然工作中的代码是不能外泄的,下面示例我们仅以开源的element ui的基础上进行尝试,在这些尝试中给我的思考及启发分享给大家,如有不完善或者错误的地方,还请各位同僚不吝赐教,一起共建良好且高效的开发环境。
官网地址
确保你安装了最新版本的 Node.js,然后在命令行中运行以下命令 (不要带上 > 符号)
装不上的话,看看自己是否安装了科学上网的工具,或者防火墙之类的东西。
npm init vue@latest
这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示
✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
Scaffolding project in ./<your-project-name>...
Done.
为了让项目简单,这里我都选的no
npm install element-plus --save
找到项目中的main.js文件。(注意此处是全局引入到项目中插件的地方,由于我们项目中只引入了element-plus,所以可以全局替换。
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
一切配置好后,我们就可以直接在项目中使用插件了。
首先我们知道vue3的主要标志是组合式api,也就是setup()函数。
所以在组件中我们就需要创建一个setup()。
如下:
<template>
</template>
<script>
export default {
setup() {
},
};
</script>
<style scoped>
</style>
但是我们看到element-plus上长这样
<template> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="Date" width="180" /> <el-table-column prop="name" label="Name" width="180" /> <el-table-column prop="address" label="Address" /> </el-table> </template> <script lang="ts" setup> const tableData = [ { date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles', }, { date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles', }, { date: '2016-05-04', name: 'Tom', address: 'No. 189, Grove St, Los Angeles', }, { date: '2016-05-01', name: 'Tom', address: 'No. 189, Grove St, Los Angeles', }, ] </script>
很多像我这样的小伙伴,可能就会迷惑了,这样抄行吗?
答案是可行的,但是个人经过学习发现这样抄并不好。
首先:后面我们越抄代码越乱,不易于维护。
其次:和vue差距太大了,我们不太习惯。
为了习惯我们可以将上面的代码改成这样。
<template> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="Date" width="180" /> <el-table-column prop="name" label="Name" width="180" /> <el-table-column prop="address" label="Address" /> </el-table> </template> <script> import { reactive, toRefs } from "vue"; export default { setup() { const state = reactive({ tableData: [ { date: "2016-05-03", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-02", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-04", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-01", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, ], }); return toRefs(state); }, }; </script> <style scoped> </style>
发现上面的代码并没有报错。
由此我们认为上面的代码是完全可行的。此处我们就用到了vue3的reactive, toRefs两个API。
表格实在太简单,那么我们是不是可以在表格的基础上加个搜索呢?
是的
一个可以校验的表单长这个样子。
<template> <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize" status-icon > <el-form-item label="Activity name" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="Activity zone" prop="region"> <el-select v-model="ruleForm.region" placeholder="Activity zone"> <el-option label="Zone one" value="shanghai" /> <el-option label="Zone two" value="beijing" /> </el-select> </el-form-item> <el-form-item label="Activity count" prop="count"> <el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" /> </el-form-item> <el-form-item label="Activity time" required> <el-col :span="11"> <el-form-item prop="date1"> <el-date-picker v-model="ruleForm.date1" type="date" label="Pick a date" placeholder="Pick a date" style="width: 100%" /> </el-form-item> </el-col> <el-col class="text-center" :span="2"> <span class="text-gray-500">-</span> </el-col> <el-col :span="11"> <el-form-item prop="date2"> <el-time-picker v-model="ruleForm.date2" label="Pick a time" placeholder="Pick a time" style="width: 100%" /> </el-form-item> </el-col> </el-form-item> <el-form-item label="Instant delivery" prop="delivery"> <el-switch v-model="ruleForm.delivery" /> </el-form-item> <el-form-item label="Activity type" prop="type"> <el-checkbox-group v-model="ruleForm.type"> <el-checkbox label="Online activities" name="type" /> <el-checkbox label="Promotion activities" name="type" /> <el-checkbox label="Offline activities" name="type" /> <el-checkbox label="Simple brand exposure" name="type" /> </el-checkbox-group> </el-form-item> <el-form-item label="Resources" prop="resource"> <el-radio-group v-model="ruleForm.resource"> <el-radio label="Sponsorship" /> <el-radio label="Venue" /> </el-radio-group> </el-form-item> <el-form-item label="Activity form" prop="desc"> <el-input v-model="ruleForm.desc" type="textarea" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm(ruleFormRef)" >Create</el-button > <el-button @click="resetForm(ruleFormRef)">Reset</el-button> </el-form-item> </el-form> </template> <script lang="ts" setup> import { reactive, ref } from 'vue' import type { FormInstance, FormRules } from 'element-plus' const formSize = ref('default') const ruleFormRef = ref<FormInstance>() const ruleForm = reactive({ name: 'Hello', region: '', count: '', date1: '', date2: '', delivery: false, type: [], resource: '', desc: '', }) const rules = reactive<FormRules>({ name: [ { required: true, message: 'Please input Activity name', trigger: 'blur' }, { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' }, ], region: [ { required: true, message: 'Please select Activity zone', trigger: 'change', }, ], count: [ { required: true, message: 'Please select Activity count', trigger: 'change', }, ], date1: [ { type: 'date', required: true, message: 'Please pick a date', trigger: 'change', }, ], date2: [ { type: 'date', required: true, message: 'Please pick a time', trigger: 'change', }, ], type: [ { type: 'array', required: true, message: 'Please select at least one activity type', trigger: 'change', }, ], resource: [ { required: true, message: 'Please select activity resource', trigger: 'change', }, ], desc: [ { required: true, message: 'Please input activity form', trigger: 'blur' }, ], }) const submitForm = async (formEl: FormInstance | undefined) => { if (!formEl) return await formEl.validate((valid, fields) => { if (valid) { console.log('submit!') } else { console.log('error submit!', fields) } }) } const resetForm = (formEl: FormInstance | undefined) => { if (!formEl) return formEl.resetFields() } const options = Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })) </script>
好烦,又是一大坨。
对此我们是不是应该和上面那个表格融合一下呢?
经过改造后长这个样子:
<template> <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize" status-icon > <el-form-item label="Activity name" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="Activity zone" prop="region"> <el-select v-model="ruleForm.region" placeholder="Activity zone"> <el-option label="Zone one" value="shanghai" /> <el-option label="Zone two" value="beijing" /> </el-select> </el-form-item> <el-form-item label="Activity count" prop="count"> <el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm(ruleFormRef)" >Create</el-button > <el-button @click="resetForm(ruleFormRef)">Reset</el-button> </el-form-item> </el-form> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="Date" width="180" /> <el-table-column prop="name" label="Name" width="180" /> <el-table-column prop="address" label="Address" /> </el-table> </template> <script> import { reactive, ref, toRefs } from "vue"; export default { setup() { const submitForm = async (formEl) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { console.log("submit!"); } else { console.log("error submit!", fields); } }); }; const resetForm = (formEl) => { if (!formEl) return; formEl.resetFields(); }; const state = reactive({ // 表格数据 tableData: [ { date: "2016-05-03", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-02", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-04", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-01", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, ], // 表单数据 ruleForm: { name: "Hello", region: "", count: "", }, // 表单校验 rules: { name: [ { required: true, message: "Please input Activity name", trigger: "blur", }, { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur", }, ], region: [ { required: true, message: "Please select Activity zone", trigger: "change", }, ], count: [ { required: true, message: "Please select Activity count", trigger: "change", }, ], }, formSize: "default", // 数字字典 options: Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })), ruleFormRef:ref(null), submitForm, //提交 resetForm,//还原 }); return toRefs(state); }, }; </script> <style scoped> </style>
上面虽然省了一些字段,但是其实已经简化整合了好多东西了。
比如:
其实所有字段都是可以存在reactive;
ruleFormRef:ref(null),可以直接使用在vue标签上的ref,并且数据中已经具备了dom树上的所有内容。
也就是在此处我们也是可以把resetForm函数改写也是可以正常使用的:
改写如下:(不再通过触发事件传值了,而是直接使用state里面的值)。
function resetForm () {
if (!state.ruleFormRef) return;
state.ruleFormRef.resetFields();
};
细心的小伙伴发现此处我们把箭头函数改成了普通函数,这是因为const会有执行顺序的问题。
如果想要避免这个问题,我们可以把const改成var。(这里涉及到了js的预编译问题)
然后代码就变成了这个样子:
<template> <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize" status-icon > <el-form-item label="Activity name" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="Activity zone" prop="region"> <el-select v-model="ruleForm.region" placeholder="Activity zone"> <el-option label="Zone one" value="shanghai" /> <el-option label="Zone two" value="beijing" /> </el-select> </el-form-item> <el-form-item label="Activity count" prop="count"> <el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm(ruleFormRef)" >Create</el-button > <el-button @click="resetForm()">Reset</el-button> </el-form-item> </el-form> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="Date" width="180" /> <el-table-column prop="name" label="Name" width="180" /> <el-table-column prop="address" label="Address" /> </el-table> </template> <script> import { reactive, ref, toRefs } from "vue"; export default { setup() { var submitForm = async (formEl) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { console.log("submit!"); } else { console.log("error submit!", fields); } }); }; var resetForm = () => { if (!state.ruleFormRef) return; state.ruleFormRef.resetFields(); }; var state = reactive({ // 表格数据 tableData: [ { date: "2016-05-03", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-02", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-04", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-01", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, ], // 表单数据 ruleForm: { name: "Hello", region: "", count: "", }, // 表单校验 rules: { name: [ { required: true, message: "Please input Activity name", trigger: "blur", }, { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur", }, ], region: [ { required: true, message: "Please select Activity zone", trigger: "change", }, ], count: [ { required: true, message: "Please select Activity count", trigger: "change", }, ], }, formSize: "default", // 数字字典 options: Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })), ruleFormRef:ref(null), submitForm, //提交 resetForm,//还原 }); return toRefs(state); }, }; </script> <style scoped> </style>
上面的内容,我们承认函数已经不受编译顺序影响了,但是这也影响了我们新增const,let的初衷,为了使用const,let,我们还是直接要按顺序来的,如果想放到state下面,那么就推荐使用function。这也就回到了js的本源。
就像这样:
<template> <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize" status-icon > <el-form-item label="Activity name" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="Activity zone" prop="region"> <el-select v-model="ruleForm.region" placeholder="Activity zone"> <el-option label="Zone one" value="shanghai" /> <el-option label="Zone two" value="beijing" /> </el-select> </el-form-item> <el-form-item label="Activity count" prop="count"> <el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm(ruleFormRef)" >Create</el-button > <el-button @click="resetForm">Reset</el-button> </el-form-item> </el-form> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="Date" width="180" /> <el-table-column prop="name" label="Name" width="180" /> <el-table-column prop="address" label="Address" /> </el-table> </template> <script> import { reactive, ref, toRefs } from "vue"; export default { setup() { const submitForm = async (formEl) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { console.log("submit!"); } else { console.log("error submit!", fields); } }); }; const state = reactive({ // 表格数据 tableData: [ { date: "2016-05-03", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-02", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-04", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-01", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, ], // 表单数据 ruleForm: { name: "Hello", region: "", count: "", }, // 表单校验 rules: { name: [ { required: true, message: "Please input Activity name", trigger: "blur", }, { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur", }, ], region: [ { required: true, message: "Please select Activity zone", trigger: "change", }, ], count: [ { required: true, message: "Please select Activity count", trigger: "change", }, ], }, formSize: "default", // 数字字典 options: Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })), ruleFormRef:ref(null), submitForm, //提交 resetForm,//还原 }); function resetForm (){ if (!state.ruleFormRef) return; state.ruleFormRef.resetFields(); }; return toRefs(state); }, }; </script> <style scoped> </style>
其实讲到上面还不过瘾
我们还发现setup的返回其实还可以通过解构的方法这样写的。
<script> import { reactive, ref, toRefs } from "vue"; export default { setup() { const submitForm = async (formEl) => { if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { console.log("submit!"); } else { console.log("error submit!", fields); } }); }; const state = reactive({ // 表格数据 tableData: [ { date: "2016-05-03", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-02", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-04", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, { date: "2016-05-01", name: "Tom", address: "No. 189, Grove St, Los Angeles", }, ], // 表单数据 ruleForm: { name: "Hello", region: "", count: "", }, // 表单校验 rules: { name: [ { required: true, message: "Please input Activity name", trigger: "blur", }, { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur", }, ], region: [ { required: true, message: "Please select Activity zone", trigger: "change", }, ], count: [ { required: true, message: "Please select Activity count", trigger: "change", }, ], }, formSize: "default", // 数字字典 options: Array.from({ length: 10000 }).map((_, idx) => ({ value: `${idx + 1}`, label: `${idx + 1}`, })), ruleFormRef:ref(null), submitForm, //提交 // resetForm,//还原 }); function resetForm (){ if (!state.ruleFormRef) return; state.ruleFormRef.resetFields(); }; return{...toRefs(state),resetForm} ; }, }; </script>
好了,今天就到这啦
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。