
父组件如何使用 代码中注释很多, 应该很容易理解
- <div>
- <wgySearch
- v-model="searchDefault"
- :fields="searchFields"
- @reset="reset"
- @submit="submit"
- >
-
- <template slot="delivery">
- <el-switch v-model="searchDefault.delivery" />
- template>
- wgySearch>
-
- div>
-
-
- <script>
- import wgySearch from './wgySearch';
-
- // 这两个组件是给search组件传递的
- import wgySelect from './wgySelect';
- import wgyDatePicker from './wgyDatePicker';
-
- data 中
- // 搜索栏中的默认值
- searchDefault: {
- name: '',
- region: '',
- delivery: '',
- date: '',
- },
- // 配置项
- searchFields: [
- {
- label: '活动名称',
- model: 'name',
- },
- {
- label: '活动区域',
- model: 'region',
- template: {
- // tpl传一个wgySelect组件,专门用来只用来传数据
- tpl: wgySelect,
- attrs: {
- multiple: true,
- list: [
- { label: 'A', value: 1 },
- { label: 'B', value: 2 },
- ],
- },
- },
- },
- {
- label: '即时配送',
- slot: 'delivery', // 这里配置项是slot, 模板中才能使用slot对应的字段
- },
- {
- label: '活动时间',
- model: 'date',
- template: {
- tpl: wgyDatePicker,
- attrs: {
- type: 'daterange',
- 'value-format': 'timestamp',
- },
- },
- },
- ],
-
-
- reset和submit这两方法是搜索和重置的时候调用的
- script>
wgySelect组件
- <el-select
- v-model="value1"
- v-bind="$attrs"
- @input="input"
- >
- <el-option
- v-for="item in list"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- el-select>
- <script>
- export default {
- name: 'WgySelect',
-
- props: {
- value: {
- type: [Number, String, Array],
- required: true,
- },
- list: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- value1: this.value,
- };
- },
- methods: {
- input(val) {
- this.$emit('input', val);
- },
- },
- };
- script>
wgyDatePicker组件
- <el-date-picker
- v-model="value1"
- range-separator="至"
- start-placeholder="开始日期"
- v-bind="$attrs"
- end-placeholder="结束日期"
- @input="input"
- />
-
- <script>
- export default {
- name: 'WgyDatepicker',
-
- props: {
- value: {
- type: [Array, Number, String],
- default: () => '',
- },
- },
- data() {
- return {
- value1: this.value,
- };
- },
- methods: {
- input(val) {
- this.$emit('input', val || '');
- },
- },
- };
- script>
wgySearch 这个就是最主要的搜索组件了
- <div>
-
- <div
- v-if="$slots.operatorLeft || $slots.operatorRight"
- class="slot-operator clearfix"
- >
- <div class="pull-left">
- <slot name="operatorLeft">slot>
- div>
- <div class="pull-right">
- <slot name="operatorRight">slot>
- div>
- div>
-
- <div class="form-ctn">
- <el-form
- :ref="formAttrs.ref || 'form'"
- :model="formData"
- :inline="true"
- :label-width="getLabelWidth"
- label-position="right"
- v-bind="formAttrs"
- size="small"
- @submit.native.prevent="submit"
- @reset.native.prevent="reset"
- >
- <div :style="getWrapperStyle">
- <el-form-item
- v-for="(field, index) in innerFields"
- :key="`${field.model || field.slot}${index}`"
- :prop="field.prop"
- :label="field.label"
- :rules="field.rules"
- :style="{display: (index + 1) > maxShowNum && !showAll ? 'none' : 'inline-block'}"
- >
-
- <wgy-template
- v-if="field.template"
- v-model="formData[field.model]"
- :tpl="field.template.tpl"
- :style="{width: `${getTempWidth(field.template.attrs)}px`}"
- :attrs="field.template.attrs"
- v-on="field.template.events"
- />
-
-
- <template v-else>
-
- <slot
- v-if="field.slot"
- :name="field.slot"
- >slot>
- <el-input
- v-else
- v-model.trim="formData[field.model]"
- :placeholder="field.placeholder"
- clearable
- class="w180"
- v-bind="field.itemAttrs"
- />
- template>
- el-form-item>
- <slot name="suffixCustomitems">slot>
- <div
- :class="btnClass"
- :style="getBtnStyle"
- >
- <el-button
- v-if="fields.length > maxShowNum"
- type="text"
- @click="showAll = !showAll"
- >
- <i :class="showAll ? 'el-icon-caret-top' : 'el-icon-caret-bottom'">i>
- {{ showAll ? '收起' : '展开' }}
- el-button>
- <el-button
- v-if="showSubmit"
- type="primary"
- native-type="submit"
- class="search-btn"
- >
- {{ leftButton }}
- el-button>
- <el-button
- v-if="showReset"
- native-type="reset"
- class="reset-btn"
- >
- {{ rightButton }}
- el-button>
- <span class="ml10">
- <slot name="searchbtn">slot>
- span>
- div>
- div>
- el-form>
- div>
-
- <div
- v-if="withDivider"
- class="divider"
- >div>
- div>
-
- <script>
- import wgyTemplate from './wgyTemplate';
-
- export default {
- components: {
- wgyTemplate,
- },
- props: {
- // 绑定的值
- value: {
- type: Object,
- required: true,
- },
- leftButton: {
- type: String,
- default: () => '查询',
- },
- rightButton: {
- type: String,
- default: () => '重置',
- },
- // 每行元素个数
- lineNumber: {
- type: Number,
- default: () => 4,
- },
- // label 的宽度
- labelWidth: {
- type: String,
- default: () => '100px',
- },
- // 透传给el-form的属性配置
- formAttrs: {
- type: Object,
- default: () => ({}),
- required: false,
- },
- // 配置字段
- fields: {
- type: Array,
- required: true,
- },
- // 是否显示搜索按钮
- showSubmit: {
- type: Boolean,
- default: true,
- },
- // 是否显示重置按钮
- showReset: {
- type: Boolean,
- default: true,
- },
- // 最大默认显示搜索项个数 ,超过这个数字后会收起
- maxShowNum: {
- type: Number,
- default: 8,
- },
- // 按钮组class
- btnClass: {
- type: String,
- default: '',
- },
- // 自动包含下方的分割线(列表页常用)
- withDivider: {
- type: Boolean,
- default: true,
- },
- },
- data() {
- return {
- // 绑定的值
- formData: this.value,
- // 配置字段 < 默认显示搜索项个数
- showAll: this.fields.length < this.maxShowNum,
- };
- },
- computed: {
- // 处理placeholder
- innerFields() {
- return this.fields.map((field) => {
- const { template, label } = field;
- // 根据是否有template属性,生成默认的placeholder
- const defaultPlaceholder = template ? `请选择${label}` : `请输入${label}`;
-
- if (template) {
- // 如果有template属性,但没有attrs属性,初始化attrs为一个空对象
- template.attrs = template.attrs || {};
- // 如果attrs对象没有placeholder属性,使用默认的placeholder
- template.attrs.placeholder = template.attrs.placeholder || defaultPlaceholder;
- } else {
- // 如果没有template属性,且没有placeholder属性,使用默认的placeholder
- field.placeholder = field.placeholder || defaultPlaceholder;
- }
- return field;
- });
- },
- getWrapperStyle() {
- // 动态改变该元素的布局
- return {
- display: 'flex',
- flexWrap: 'wrap',
- };
- },
- getIsSameLine() {
- // 判断表单的字段数量是否小于等于每行的元素个数并且字段数量不能被每行的元素个数整除
- const { fields, lineNumber } = this;
- return fields.length <= lineNumber && !(fields.length % lineNumber === 0);
- },
- // 按钮的样式
- getBtnStyle() {
- return {
- textAlign: this.getIsSameLine ? 'left' : 'right',
- flex: 1,
- minWidth: '220px',
- marginBottom: '10px',
- };
- },
- /**
- * 计算表单标签的宽度
- * 如果用户已经设置了 labelWidth,则直接返回用户设置的值
- * 否则,根据表单字段的标签长度动态计算标签宽度
- */
- getLabelWidth() {
- if (this.labelWidth) {
- return this.labelWidth;
- }
- // 获取表单字段标签的最大长度
- const maxLength = Math.max(...this.fields.map((item) => item.label.length));
- if (maxLength <= 4) {
- return '80px';
- }
- if (maxLength > 4 && maxLength <= 6) {
- return '90px';
- }
- if (maxLength > 6 && maxLength < 10) {
- return '120px';
- }
- return '100px';
- },
- validate() {
- return this.$refs.form.validate;
- },
- },
- watch: {
- // 外层变化实时通知内部, 内部变化实时通知外部
- value: {
- deep: true,
- handler(newVal) {
- this.formData = newVal;
- },
- },
- formData: {
- deep: true,
- handler(newVal) {
- this.$emit('input', newVal);
- },
- },
- },
- methods: {
- // 搜索
- submit() {
- this.$emit('submit');
- },
- // 重置
- reset() {
- this.$emit('reset');
- },
- /*
- 获取每个输入框的宽度
- 如果attrs中有传入, 使用传入的宽度
- 如果是日期选择器,宽度是210
- 如果是日期时间选择器,宽度是340
- 其他的宽度都是180
- */
- getTempWidth(attrs = {}) {
- const { width, type } = attrs;
- if (width) {
- return width;
- }
- if (type === 'daterange') {
- return 210;
- }
- if (type === 'datetimerange') {
- return 340;
- }
- return 180;
- },
- },
- };
- script>
-
- <style lang="scss">
- .search-box {
- background: #fff;
- .slot-operator {
- border-bottom: 1px solid #eee;
- padding-bottom: 10px;
- margin-bottom: 10px;
- }
- .form-ctn {
- position: relative;
- .search-btn,
- .reset-btn {
- min-width: 0;
- }
- .reset-btn {
- margin-left: 8px;
- }
- }
- .el-form-item {
- margin-bottom: 16px;
- white-space: nowrap;
- }
- .el-form-item--small .el-form-item__label {
- padding-right: 5px;
- }
- .el-form-item--small .el-form-item__content {
- min-width: 180px;
- .el-date-editor--daterange .el-range-input {
- min-width: 70px;
- }
- }
- }
- .divider {
- box-sizing: border-box;
- background-color: #fafafb;
- height: 10px;
- border-top: 1px solid #eeeeee;
- border-bottom: 1px solid #eeeeee;
- }
- style>
wgyTemplate 是wgySearch组件中的子组件
- <component
- :is="dynamicComponent"
- :value="value"
- v-bind="attrs"
- v-on="listeners"
- />
-
- <script>
-
- export default {
- name: 'WgyTemplate',
- props: {
- tpl: {
- type: [String, Object],
- required: true,
- },
- value: {
- type: [Number, String, Object, Array],
- required: true,
- },
- attrs: {
- type: Object,
- default: () => ({}),
- },
- },
- computed: {
- // 要渲染的组件
- dynamicComponent() {
- return this.tpl;
- },
- // 收集所有需要绑定到动态组件上的事件监听器
- listeners() {
- return {
- input: this.input,
- ...this.$listeners,
- };
- },
- },
- methods: {
- input(value) {
- this.$emit('input', value);
- },
- },
- };
- script>