携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
因为后台管理系统中各种页面布局差不多,并且搜索模块用的地方很多,每次都重新写的话,重复工作太多,所以就封装一个组件,有很多不足,请见谅,并且提提建议
ps: vue3+ts的版话,因为目前我还在学习,所以就先用vue+element在项目中使用啦
1.封装一个叫 searchForm 的组件来适配常用的,(可以自行进行适当添加不同的内容)
<template>
<div class="hs-from">
<div class="header">
<slot name="header" />
</div>
<el-form :label-width="labelWidth">
<el-row>
<div v-for="item in formItems" :key="item.label">
<el-col v-bind="colLayout">
<el-form-item :label="item.label" :style="itemStyle">
<!-- 输入框 -->
<template
v-if="item.type === 'input' || item.type === 'password'"
>
<el-input
:show-password="item.type === 'password'"
:placeholder="item.placeHolder"
autocomplete="off"
:clearable="clearabled"
:value="formData[`${item.field}`]"
@input="handleModelValue($event, item.field)"
/>
<!-- {{ formData[`${item.field}`] }} -->
</template>
<!-- 下拉框 -->
<template v-else-if="item.type === 'select'">
<el-select
:value="formData[`${item.field}`]"
@input="handleModelValue($event, item.field)"
:clearable="clearabled"
>
<el-option
style="width: 100%"
v-for="option in item.options"
:key="option.id"
:label="option.label"
:value="option.id"
/>
</el-select>
</template>
<!-- 时间范围 type='daterange' -->
<template v-if="item.type === 'datePicker'">
<el-date-picker
:value="formData[`${item.field}`]"
@input="handleModelValue($event, item.field)"
:clearable="clearabled"
style="width: 100%"
v-bind="item.otherOptions"
>
</el-date-picker>
</template>
</el-form-item>
</el-col>
</div>
<!-- 一行只有两个form-item时按钮展示在一行 -->
<template v-if="formItems.length < 3">
<slot name="inlineButton" />
</template>
</el-row>
</el-form>
<div class="hs-footer">
<slot name="footer" />
</div>
</div>
</template>
<script>
export default {
name: "searchFrom",
// module: { // 改变要触发的事件名称
// event: "changeValue",
// },
props: {
// 双向绑定的值 vue2中的默认是value,vue3中的是modelValue
value: {
type: Object,
required: true,
},
// formItem的配置对象参数
formItems: {
type: Array,
default: () => [],
},
// 是否显示清除按钮
clearabled: {
type: Boolean,
default: true,
},
// label文本的宽度
labelWidth: {
type: String,
default: "100px",
},
// 每个form-item之间的距离
itemStyle: {
type: Object,
default: () => ({
padding: "20px 30px",
}),
},
// 适配
colLayout: {
type: Object,
default: () => ({
xl: 6,
lg: 8,
md: 12,
sm: 24,
xs: 24,
}),
},
},
// created() {
// console.log(this.value);
// },
data() {
return {
formData: this.value,
};
},
methods: {
handleModelValue(value, field) {
// value: 输入的值,field:要改变的字段
this.$emit("changeValue", { value, field });
},
},
};
</script>
<style></style>
在封装的时候可以通过 v-bind 来传入一个对象的所有 property,在二次封装组件时非常好用
可以通过 type 的类型来判断展示不同的内容
:value="formData[
${item.field}]"@input="handleModelValue($event, item.field)",实现双向绑定,父级监听
1.3 v-model的组件传值 vue3和vue2的区别
Vue3和vue2实现组件间双向绑定的方式不太一样,其原因是因为v-model内部本质的变化,vue2的v-model默认的属性名是value,事件是input,vue3的v-model默认的属性名是modelValue,事件名是update:modelValue,接下来使用v-model的属性名和事件名来实现组件之间的双向绑定。
vue3的双向绑定
当在自定义组件中使用v-model时,组件接收一个属性modelValue的值,然后通过触发update:modelValue事件来更新该值:
<custom-from v-model="msg"></custom-from>
<!-- 等价于 -->
<custom-from :model-value="msg" @update:model-value="msg = $event"></custom-from>
<!-- 建议命名按照kebab-cased规范,如:model-value,而不是modelValue -->
vue2的双向绑定
当在自定义组件中使用v-model时,组件接收一个属性value的值,然后通过触发input事件来更新该值,这样便实现了v-model:
<custom-from v-model="msg"></custom-from>
<!-- 等价于 -->
<custom-from :value="msg" @input="msg = $event"></custom-from>
1.1 传递静态或动态 Prop(单个传值)
// 静态
<blog-post title="My journey with Vue"></blog-post>
可以通过 `v-bind` 动态赋值
<blog-post v-bind:title="post.title + ' by ' + post.author.name" \>
1.2 传入一个对象的所有 property
如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:
post: { id: 1, title: 'My Journey with Vue' }
下面的模板:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post v-bind:id="post.id" v-bind:title="post.title" ></blog-post>
2. 注册全局组件 (因为通用吗,所以就全局注册啦)
创建一个注册全局组件的 js文件
import SearchFrom from './FormTable/searchFrom.vue'
import Vue from 'vue'
export default {
install(){
Vue.component("SearchFrom",SearchFrom)
}
}
在manin.js中注册一下,因为vue中注册组件也是执行,install 方法,所以上面就导出一个 包含install 的对象
// 全局注册组件 main.js
import globalComponents from './components/globalComponents'
Vue.use(globalComponents)
3. 写一个配置对象,传给 SearchFrom 组件的 props
因为单独绑定看着很多字段,合并写一个对象,通过 v-bind 进行绑定
// 合并一个对象 porps 通过v-bind绑定传给组件
export default { //将所有要传的props合并为一个对象,通过v-bind传给 searchFrom 组件
formItems: [
{
field:'time', // 字段名称
label: "收款时间:",
type: "datePicker", // 展示类型
otherOptions: {
startPlaceholder: "开始时间", // 起始时间占位
endPlaceholder: "结束时间",
type: "daterange", // 显示类型
format: "yyyy 年 MM 月 dd 日", // 显示在输入框中的格式
valueFormat: "timestamp", // 绑定值的格式。不指定则绑定值为 Date 对象
unlinkPanels:true , // 是否解除联动
defaultTime:['00:00:00', '23:59:59'] // 起始时间和结束时间的具体时刻
},
},
{
field:'shop_name',
label: "商家名称:",
placeHolder: "请输入商家名称",
type: "input",
},
// {
// filed:'name',
// type:'select',
// label:'下拉框:',
// placeHolder:'请选择',
// 下拉框的选项
// options:[
// {label:'下拉选项1',id:1},
// {label:'下拉选项2',id:2},
// ]
// }
],
// clearabled:false,
itemStyle: {
padding: "0px 5px",
},
colLayout: {
span: 10,
},
}
展示视图:
4. 使用+ v-model组件传值的数据展示
<template>
<!-- 搜索项 -->
<SearchForm
v-bind="searchFormConfig"
v-model="formData"
@changeValue="changeValue"
>
<template #inlineButton>
<el-row class="FR">
<el-button type="primary" @click="search">搜索</el-button>
<el-button>导出</el-button>
</el-row>
</template>
</SearchForm>
<template>
<script>
import searchFormConfig from "./config/searchFrom"; // 搜索项的配置文件选项
export default {
name: "technicalServiceFeeStatistics",
data() {
return {
searchFormConfig, // 搜索项的配置对象
formData: {
// 创建一个 搜索参数的 对象
shop_name: "",
time: "",
page: 1,
page_size: 10,
},
};
},
// 这样增加对象中的字段,vue无法进行双向绑定
// mounted() {
// // 双向绑定的属性应该是由配置文件的field来决定
// const formItems = props.searchFormConfig?.formItems
// const formOriginData = {}
// for (const item of formItems) {
// formOriginData[item.field] = ''
// }
// this.formData = ref(formOriginData)
// },
methods: {
// 修改formData里面字段的值
changeValue({ value, field }) {
this.formData[field] = value;
console.log(this.formData);
},
},
};
</script>
在 SearchFrom 中使用 this.$emit("changeValue", { value, field });,父组件通过 changeValue事件改变字段值,实现单向数据流