2021.9.3
坑61(element-plus、根据视口尺寸隐藏元素):文档要求引入文件 import 'element-plus/lib/theme-chalk/display.css',其中地址错误,查看包文件结构后,确认地址应该为:
import 'element-plus/theme-chalk/display.css';
地址改变的原因是element-plus更新到1.1.0-beta.1版本的时候的变化。详细见: Breaking changes made in 1.1.0-beta.1 · Discussion #3020 · element-plus/element-plus · GitHub ,可以看到element-plus的文件组织形式/项目结构发生了较大变化。
坑62(vue3、v-model、props、emit、二次封装、父组件和子组件双向传递数据、el-form-item、el-input、el-checkbox-group、el-radio-group):目标是封装el-form-item,而el-form-item中又包含了el-input、el-checkbox-group、el-radio-group(当然更深入还有el-checkbox、el-radio)。
首先看一下封装前父组件中el-form-item的使用,代码量较多,数据存放在dataForm中,如下:
<el-form-item prop='inputData'>
<el-input class='isInput'
v-model="dataForm.inputData"
placeholder="输入"
type="text"
clearable autocomplete>
</el-input>
</el-form-item>
<el-form-item prop='checkboxData'>
<el-checkbox-group class='isSelectbox'
v-model='dataForm.checkboxData' >
<el-checkbox label='复选1'></el-checkbox>
<el-checkbox label='复选2' ></el-checkbox>
<el-checkbox label='复选3'></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item prop='radioData'>
<el-radio-group class='isSelectbox'
v-model='dataForm.radioData'>
<el-radio label='单选1'></el-radio>
<el-radio label='单选2'></el-radio>
</el-radio-group>
</el-form-item>
之后开始封装,期间踩坑无数,记录一些要点:
1、el-input、el-checkbox-group、el-radio-group这些组件都使用了v-model进行数值的双向绑定,而不是使用html中原生input的value。
2、父组件传值到子组件用props,子组件传值到父组件用emit。
3、父组件props传值的时候,使用v-model。
循序渐进:在多次尝试el-input的封装失败后,先尝试了原生input的封装。
子组件中,input输入框的value绑定通过props(父组件中使用了v-model)传入数据值dataModel。在input输入框值改变触发input事件时,通过emit发送dataModel更新事件给父组件,更新dataModel的值为$event.target.value。代码如下:
<template>
<input type='text' :value='dataModel'
@input="$emit('update:dataModel',$event.target.value)" />
</template>
<script>
export default {
name: 'TestInput',
props: {
dataModel: String,
},
setup() {
}
}
父组件中调用,通过v-model绑定数据即可,代码如下:
<TestInput v-model:dataModel='inputData' />
// 等同于以下
<TestInput :dataModel='inputData' @updata:dataModel='dataModel=$event' />
另外,如果直接用v-model='inputData',不指定具体属性名称时,默认名称是modelValue。
正式封装:接下来正式进行包含el-input、el-checkbox-group、el-radio-group的el-form-item的封装。首先确认传递的props参数如下。
type:指定el-form-item中具体的组件类型,String,值为 input / checkbox / radio ;
prop:指定el-form-item的prop属性值,String;
dataModel(需要在父组件和子组件之间双向传递):指定el-form-item中具体的组件的v-model绑定的数据值,输入框String,选择组Array;
text:指定el-form-item中具体的组件的提示文本,输入框String,值绑定到placeholder,选择组Array,值循环绑定到选项的label(此处暂时以提示文本作为选项的label值;有具体需要的话,应另设一个label参数,确定每个选项的label)。
其中,数据值dataModel在父组件中会用v-model传递。
接下来是具体解决方案。
子组件中,数据值dataModel直接绑定到el组件的v-model。emit事件的触发参考element-plus各组件的文档:el-input使用input事件;el-checkbox-group和el-radio-group使用change事件。emit事件所传的值也与原生input不同,根据文档,input和change事件的参数值就是组件的数据值,即$event。代码如下:
<template>
<el-form-item :prop='prop'>
<el-input v-if='type==="input"' class='isInput'
v-model='dataModel'
@input="$emit('update:dataModel',$event)"
:placeholder="text"
type="text"
clearable autocomplete>
</el-input>
<el-checkbox-group v-else-if='type==="checkbox"' class='isSelectbox'
v-model='dataModel'
@change="$emit('update:dataModel',$event)">
<el-checkbox v-for='item in text' :key="item"
:label='item'></el-checkbox>
</el-checkbox-group>
<el-radio-group v-else-if='type==="radio"' class='isSelectbox'
v-model='dataModel'
@change="$emit('update:dataModel',$event)">
<el-radio v-for='item in text' :key="item"
:label='item'></el-radio>
</el-radio-group>
</el-form-item>
</template>
<script>
export default {
name: 'SearchItem',
props: {
type: String,
prop: String,
dataModel: [String, Array],
text: [String, Array],
},
setup(){
},
}
</script>
需要注意的一点是props的类型判断,根据前文定下的来。
另外,el-checkbox和el-radio,现在因为没有配置显示值,默认显示值是和label相同的。如有需要,label及显示提示文本也可以分开配置。
父组件中调用,通过v-model绑定dataModel数据值,并配置其他各项props参数,代码如下:
<SearchItem type='input' prop='inputData'
v-model:dataModel='dataForm.inputData'
text='输入' />
<SearchItem type='checkbox' prop='checkboxData'
v-model:dataModel='dataForm.checkboxData'
:text='["复选1","复选2","复选3"]' />
<SearchItem type='radio' prop='radioData'
v-model:dataModel='dataForm.radioData'
:text='["单选1","单选2"]' />
现在一些样式也可以移动到子组件中了,关于表单样式,见坑60(el-form、inline模式、元素高度不统一、元素垂直间距不统一),链接: 踩坑记18 vue 组件折叠 v-show | 深度合并对象 deepmerge | el-checkbox-group size设置无效 | el-form中元素高度、垂直间距不统一_Alloom的博客-CSDN博客
参考一览:
Props | Vue.js (vuejs.org) vue3文档:props类型
Props | Vue.js (vuejs.org) vue3文档:props验证
组件基础 | Vue3中文文档 - vuejs (vue3js.cn) vue3文档:在自定义组件中使用v-model
v-model | Vue.js (vuejs.org) vue3文档:3.x语法下的v-model
组件 | Element (element-plus.org) element-plus文档:Input 输入框
组件 | Element (element-plus.org) element-plus文档:Checkbox 多选框
组件 | Element (element-plus.org) element-plus文档:Radio 单选框
Vue3组件(三)把别人的组件拿过来再封装一下 - 简书 (jianshu.com)
Vue3.x + Vite2.x 入门实战 03:二次封装el-input组件 - 掘金 (juejin.cn)
el-input 输入框不能输入值_sinat_23536373的博客-CSDN博客_el-input无法输入 vue2的
element-ui组件的二次封装 - 简书 (jianshu.com) vue2的
坑63(vue、vite、import、路径、Vetur):引入vue组件文件时Vetur报错(但可以正常运行),引入代码如下:
import AItem from '../../../components/widgets/util/AItem.vue'
错误信息如下:
File name 'g:/Users/Administrator/VueProjects/xxx-web/src/components/widgets/util/AItem.vue' differs from already included file name 'g:/Users/Administrator/VueProjects/xxx-web/src/components/widgets/util/aItem.vue' only in casing.
The file is in the program because:
Root file specified for compilation
Imported via '../../../components/widgets/util/AItem.vue' from file 'g:/Users/Administrator/VueProjects/xxx-web/src/views/system/user/index.vue'Vetur(1149)
可以知道Vetur报错是因为两个文件名仅大小写不同,但都用于编译。这是因为修改文件名导致的:从aItem.vue变为AItem.vue。
解决方法一(推荐):关闭vs code,重新打开就好了。
解决方案二:警用Vetur。可以尝试改用Volar,实验了一下修改文件名时,Volar不会报此错误。
解决方法三:使用别名@。关于别名配置方法见坑49( vite2、alias、路径别名 ),链接: 踩坑记14 vs code 快捷键 | vue3 vite2 alias 别名设置_Alloom的博客-CSDN博客。代码如下:
import AItem from '@/components/widgets/util/AItem.vue'
一个不成功的方法:
另外参考了此篇 Vue 引入路径正确的,但一直报错: Already included file name ‘××ב differs from file name ‘××ב only in casing._estrusKing的博客-CSDN博客 中,去掉.vue后缀的方法,但运行会报错,如下:
[plugin:vite:import-analysis] Failed to resolve import "../../../components/widgets/util/AItem" from "src\views\system\user\index.vue". Does the file exist?
推测可能是使用vite的原因,import模式有些不同。
by 莫得感情踩坑机(限定)