Vue, JSX encapsulates generic query components

There will be query conditions above the management system list, generally long about the same

The previous approach was to write every page again, too much trouble!

Take some time to encapsulate a generic, customizable query component and document it

start

Idea:

  1. There is a default query box
  2. Query box through parameter configuration
  3. Filter certain queries by parameters
  4. You can customize query conditions by using parameters
  5. Change the size of the query box with parameters

After designing the second and third points above, I felt a little conflict, but later I thought it would be more convenient to keep them

design

Default query box

I designed five default query boxes based on project considerations

Start time, End time, User name, Contact information (mobile phone number), and Time range (select start and end time at the same time)

StartTime respectively, and the corresponding field name endTime, userName, and contactNumber, timeSlot (of course this a few fields need and back-end for himself, our back-end encapsulates the general query classes)

The time period should have the most recent time (last week, last month, last three months)

Query box through parameter configuration

Props design = > layout

Through the layout setting layout, the default value is all the query box startTime, endTime, userName, contactNumber, timeSlot

Filter certain queries by parameters

Props design = > exclude

Exclude to exclude certain query boxes. The default value is [].

You can customize query conditions by using parameters

Props design = > the custom

Use Custom to render specific query criteria

Custom should be an array, and each item in the array should contain type(specify the render type),valKey(return field name), hintText(placeholder)

Of course, if custom needs to render select, then options must exist

Change the size of the query box with parameters

Props design = > the size

Changing the size of the input field by size should be one of “mini”, “small”, or “medium” (because we are using Element UI).

The final code

The final design is as follows

<script>

/ * *

 * zhuzhaofeng

* Checks if the incoming data is a string

* @param {Object} o need to test data

* /

const isStr = o =>

  Object.prototype.toString.call(o) === "[object String]";



/ * *

 * zhuzhaofeng

* Check if the incoming data is an object

* @param {Object} o need to test data

* /

const isObj = o =>

  Object.prototype.toString.call(o) === "[object Object]";



const customItemTypes = [

    "input",

    "select",

    "date",

    "dates",

    "time",

    "datetime",

    "year",

    "week",

    "month"

];



export default {

    name: "SearchGroup",

    props: {

/ / layout

        layout: {

            type: Array,

// The default value is the same as LAYIUTS in data

            default: () => [

                "startTime",

                "endTime",

                "userName",

                "contactNumber",

                "timeSlot"

            ]

        },

/ / not included

        exclude: {

            type: Array,

            default: () => []

        },

// Layout size

        size: {

            type: String,

            default: "small",

validator: val => ["mini", "small", "medium"].indexOf(val) ! = = 1

        },

/ * *

* Customize the search box

* support input | | the select date | dates | time | datetime during | | week | the month

* Data format:

         * [{

* type: String (' input | | the select date | dates | time | datetime during | | week | the month ') type,

* hintText:String prompt text,

* valKey:String binds the value field to the key corresponding to the final value

*}]

         * Example

         *  <SearchGroup

         *      :custom="[{

         *      type: 'input',

         *      valKey: 'customInput',

* hintText: 'Custom input box'

         *  },{

         *      type: 'date',

         *      valKey: 'customDate',

* hintText: 'Custom date'

         *  },{

         *      type: 'datetime',

         *      valKey: 'customDateTime',

* hintText: 'Custom date and time'

         *  },{

         *      type: 'time',

         *      valKey: 'customTime',

* hintText: 'custom time'

         *  },{

         *      type: 'dates',

         *      valKey: 'customDates',

* hintText: 'multiple times'

         *  },{

         *      type: 'year',

         *      valKey: 'customYear',

* hintText: 'Select year'

         *  },{

         *      type: 'month',

         *      valKey: 'customMonth',

* hintText: 'Select month 312312'

         *  },{

         *      type: 'week',

         *      valKey: 'customWeek',

* hintText: 'Select week'

*}]"

* / >

* /

        custom: {

            type: Array,

            default: () => []

        }

    },

    data() {

        return {

/ * *

* Collection of all query boxes

* The order of this array feels like the render order

* To add a new type, define a type in this array

* /

            LAYOUTS: [

                "startTime",

                "endTime",

                "timeSlot",

                "userName",

                "contactNumber"

].

            searchData: {

/ / user name

                userName: "",

// Start time

                startTime: "",

// End time

                endTime: "",

// Contact number

                contactNumber: ""

            },

// Time range Select configuration parameters

            timeSlotPickerOptions: {

                shortcuts: [

                    {

                        text: this.$i18n.t("searchGroup.nearlyAWeek"),

                        onClick(picker) {

                            const end = new Date();

                            const start = new Date();

                            start.setTime(

                                start.getTime() - 3600 * 1000 * 24 * 7

                            );

                            picker.$emit("pick", [start, end]);

                        }

                    },

                    {

                        text: this.$i18n.t("searchGroup.nearlyAMonth"),

                        onClick(picker) {

                            const end = new Date();

                            const start = new Date();

                            start.setTime(

                                start.getTime() - 3600 * 1000 * 24 * 30

                            );

                            picker.$emit("pick", [start, end]);

                        }

                    },

                    {

                        text: this.$i18n.t("searchGroup.nearlyThreeMonths"),

                        onClick(picker) {

                            const end = new Date();

                            const start = new Date();

                            start.setTime(

                                start.getTime() - 3600 * 1000 * 24 * 90

                            );

                            picker.$emit("pick", [start, end]);

                        }

                    }

                ]

            }

        };

    },

    computed: {

        getCurrLayout() {

            let result = [];

// Handle layout exclude

            for (const item of this.LAYOUTS) {

                if (

                    this.layout.indexOf(item) > -1 &&

                    this.exclude.indexOf(item) === -1

                )

                    result.push(item);

            }

// Handle special judgments

/ * *

* If timeSlot exists

* And startTime exists in layout

* Delete timeSlot from result

* /

            if (

                result.indexOf("timeSlot") > -1 &&

                result.indexOf("startTime") > -1

            ) {

                result.splice(result.indexOf("timeSlot"), 1);

            }

/ * *

* If endTime exists

* Then startTime must exist in result

* otherwise delete endTime from result

* /

            if (

                result.indexOf("endTime") > -1 &&

                result.indexOf("startTime") === -1

            ) {

                result.splice(result.indexOf("endTime"), 1);

            }

            return result;

        },

        getCustomLayout() {

// Verify data

            this.validationCustomData(this.custom);

// Bind data

            this.bindCustomData(this.custom);

            return this.custom;

        }

    },

    methods: {

        handlerFunc(command) {

// If it is reset clear

            this.$refs['searchForm'].resetFields();

            let data = JSON.parse(JSON.stringify(this.searchData));

            this.$emit("command", command, this.searchData);

        },

/ *

* Build method set S

         * zhuzhaofeng

* /

        buildFormItemInput(key, hintText) {

            return (

                <el-form-item>

                    <el-input

                        clearable

                        vModel={this.searchData[key]}

                        placeholder={hintText}

                    />

                </el-form-item>

            );

        },

        buildFormItemDate(key, hintText, type = "date") {

            return (

                <el-form-item>

                    <el-date-picker

                        vModel={this.searchData[key]}

                        type={type}

                        placeholder={hintText}

                    />

                </el-form-item>

            );

        },

        buildFormItemDateRange(key) {

            return (

                <el-form-item>

                    <el-date-picker

                        vModel={this.searchData[key]}

                        type="daterange"

                        align="right"

                        unlink-panels

Range - the separator = "to"

Start-placeholder =" start time"

End-placeholder =" end time"

                        picker-options={this.timeSlotPickerOptions}

                    ></el-date-picker>

                </el-form-item>

            );

        },

// build method set E

/ * *

* Validate custom data data types

* /

        validationCustomData(arr) {

/ / traverse the custom

            arr.map(item => {

// 1. custom each item must be an object

/ / use the Object. The prototype. ToString. Call () detection

if (! isObj(item))

                    throw new Error("Custom item should be an <Object>");

// 2. Custom Item must have two parameters: type and valKey

// type specifies the type to render. ValKey specifies the key to return the data.

                let keys = Object.keys(item);

                if (keys.indexOf("type") < 0 || keys.indexOf("valKey") < 0)

                    throw new Error(

                        "Custom item must have 'type' and 'valkey'"

                    );

// 3. After the above conditions are true, test the data type of each item

// Check only useful parameters

// Prevent illegal data binding

// Check whether type and valKey exist in step 2

if (! isStr(item.type) || item.type.length < 1)

                    throw new Error(

                        `"Custom > item > type" should be an <String>`

                    );

                if (customItemTypes.indexOf(item.type) < 0)

                    throw new Error(

                        `"Custom > item > type" type must be ${customItemTypes.join(

                            "|"

)} `

                    );

if (! isStr(item.valKey) || item.valKey.length < 1)

                    throw new Error(

                        `"Custom > item > valKey" should be an <String>`

                    );



if (keys.indexOf("hintText") > -1 && ! isStr(item.hintText))

                    throw new Error(

                        `"Custom > item > hintText" should be an <String>`

                    );

            });

        },

/ * *

* Bind custom data to searchData

* /

        bindCustomData(val) {

// use $set or vue.set

/ / do Look: https://cn.vuejs.org/v2/guide/reactivity.html# for the object

            val.map(item => this.$set(this.searchData, item.valKey, ""));

        },

        readerCustomItem(item) {

            switch (item.type) {

                case "input":

                    return this.buildFormItemInput(

                        item.valKey,

                        item.hintText || ""

                    );

                case "date":

                    return this.buildFormItemDate(

                        item.valKey,

                        item.hintText || ""

                    );

                case "time":

                    return (

                        <el-time-picker

                            size={this.size}

                            vModel={this.searchData[item.valKey]}

                            placeholder={item.hintText}

                        />

                    );

                case "dates":

                    return this.buildFormItemDate(

                        item.valKey,

                        item.hintText || "",

                        item.type

                    );

                case "datetime":

                    return this.buildFormItemDate(

                        item.valKey,

                        item.hintText || "",

                        item.type

                    );

                case "year":

                    return this.buildFormItemDate(

                        item.valKey,

                        item.hintText || "",

                        item.type

                    );

                case "month":

                    return this.buildFormItemDate(

                        item.valKey,

                        item.hintText || "",

                        item.type

                    );

                case "week":

                    return (

                        <el-form-item>

                            <el-date-picker

Format ="yyyy week WW"

                                vModel={this.searchData[item.valKey]}

                                type={item.type}

                                placeholder={item.hintText}

                            />

                        </el-form-item>

                    );

                default:

                    return <i></i>;

            }

        },

        readerCol(child, key) {

            return (

                <el-col key={key} xs={12} sm={8} md={6} lg={4} xl={4}>

                    {child}

                </el-col>

            );

        }

    },

    render(h) {

// Fix the form item

        const formItemMaps = {

            timeSlot: this.buildFormItemDateRange("timeSlot"),

BuildFormItemInput ("userName", "userName");

StartTime: this.buildFormItemDate("startTime", "startTime"),

EndTime: this.buildFormItemDate("endTime", "endTime"),

ContactNumber: this.buildFormItemInput("contactNumber", "contact ")

        };

        return (

            <el-form

                inline={true}

                label-width="0"

                vModel={this.searchData}

                ref="searchForm"

                class="search_form"

                size={this.size}

            >

                <el-row gutter={15}>

{/** loop render input box */}

                    {this.getCurrLayout.map((item, index) => {

                        return this.readerCol(formItemMaps[item], index);

                    })}

                    {this.getCustomLayout.map((item, index) => {

                        return this.readerCol(

{/* add custom to index */}

                            this.readerCustomItem(item, index + "custom")

                        );

                    })}

{/** render query reset button */}

                    <el-col xs={12} sm={8} md={6} lg={4} xl={4}>

                        <el-form-item>

                            <el-button

                                type="primary"

                                icon="el-icon-search"

                                vOn:click={() => this.handlerFunc("submit")}

< / > query el - button >

                            <el-button

                                type="reset"

                                icon="el-icon-refresh"

                                vOn:click={() => this.handlerFunc("reset")}

> reset < / el - button >

                        </el-form-item>

                    </el-col>

                </el-row>

            </el-form>

        );

    }

};

</script>



<style lang="scss" scoped>

.search_form {

  .el-col {

    margin: 5px 0;

    .el-form-item {

      margin: 0;

      display: flex;

      width: 100%;

      /deep/ .el-form-item__content {

        flex: 1;

        overflow: hidden;

      }

    }

  }

  .el-date-editor.el-input,

  .el-date-editor.el-input__inner {

    width: 100%;

  }

}

</style>

Copy the code