前言

  • 项目中可以直接使用 elementUI 直接进行开发。
  • 当页面变多之后,每个页面写一套会发现有很多相似的地方,于是采用提取组件的方式使用,减少开发成本。
  • 页面的内容常见的是Table 数据的展示,对数据的增删改查
    • 头部为form表单,进行条件的筛选
    • 中间为内容数据的展示
    • 底部为分页菜单

Form表单

简单使用

  • 我们看下官网一个示例 Form 表单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <template>
    <el-form ref="form" :model="form" label-width="80px">
    <el-form-item label="姓名">
    <el-input v-model="form.name" style="width: 195px"></el-input>
    </el-form-item>
    <el-form-item label="国籍">
    <el-select v-model="form.region" placeholder="请选择国籍">
    <el-option label="中国" value="china"></el-option>
    <el-option label="美国" value="America"></el-option>
    </el-select>
    </el-form-item>
    <el-form-item label="爱好">
    <el-checkbox-group v-model="form.type">
    <el-checkbox label="画画" name="type"></el-checkbox>
    <el-checkbox label="吹泡泡" name="type"></el-checkbox>
    <el-checkbox label="放风筝" name="type"></el-checkbox>
    <el-checkbox label="看佩琦" name="type"></el-checkbox>
    </el-checkbox-group>
    </el-form-item>
    <el-form-item>
    <el-button type="primary" @click="onSubmit" size="small"
    >立即创建</el-button
    >
    </el-form-item>
    </el-form>
    </template>
    <script>
    export default {
    data() {
    return {
    form: {
    name: "",
    region: "",
    type: [],
    },
    };
    },
    methods: {
    onSubmit() {
    console.log(
    "提交 -> " +
    this.form.name +
    " " +
    this.form.region +
    " " +
    this.form.type,
    );
    },
    },
    };
    </script>
  • 运行结果

封装Form组件

  • 从上面的例子中可以看到至少父组件需要2份数据传入到表单组件中的:

    1. v-mode对应的数据, 这份数据是用户选择好后给父组件的,所以是双向绑定的。
    2. label 对应的数据(选项),这里是写死的,既然要封装成一个控件那么这份数据也需要父组件传过来。
  • 新建一个CommonForm.vue,作为封装Form的组件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <template>
    <!--是否行内表单-->
    <el-form :inline="inline" :model="form" ref="form" label-width="100px">
    </el-form>
    </template>

    <script>
    export default {
    //inline 属性可以让表单域变为行内的表单域
    //form 表单数据 formLabel 是标签数据
    props: {
    inline: Boolean,
    form: Object,
    formLabel: Array,
    },
    };
    </script>

    <style></style>
  • 表单的子项,类型可以有 input 输入框,Switch 开关, select选择器,单选,多选,时间日期… 等情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    <!--标签显示名称-->
    <el-form-item v-for="item in formLabel" :key="item.model" :label="item.label">
    <!--根据type来显示是什么标签-->
    <!-- switch开关 -->
    <el-switch
    v-model="form[item.model]"
    v-if="item.type === 'switch'"
    active-color="#13ce66"
    inactive-color="#ff4949"
    active-text="开"
    ></el-switch>

    <!-- 输入框 -->
    <el-input
    v-model="form[item.model]"
    :placeholder="'请输入' + item.label"
    v-if="item.type === 'input'"
    ></el-input>

    <!-- 数值输入 -->
    <el-input-number
    v-model="form[item.model]"
    v-if="item.type === 'number'"
    controls-position="right"
    :placeholder="'请输入' + item.label"
    ></el-input-number>

    <!-- 下拉选择 -->
    <el-select
    v-model="form[item.model]"
    placeholder="请选择"
    v-if="item.type === 'select'"
    >
    <!--如果是select或者checkbox 、Radio就还需要选项信息-->
    <el-option
    v-for="item in item.opts"
    :key="item.value"
    :label="item.label"
    :value="item.value"
    ></el-option>
    </el-select>

    <el-date-picker
    v-model="form[item.model]"
    type="date"
    placeholder="选择日期"
    v-if="item.type === 'date'"
    value-format="yyyy-MM-dd"
    >
    </el-date-picker>
    </el-form-item>

    <!--还可以留一个插槽,放置搜索的按钮-->
    <el-form-item>
    <slot></slot>
    </el-form-item>
  • 使用: 父组件传入props中的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- 创建一个行内表单, 带有一个输入框,属性值为keyword,标签名为空。 slot为搜索按钮 -->
    <common-form inline :formLabel="formLabel" :form="searchFrom">
    <el-button type="primary" @click="getList(searchFrom.keyword)">搜索</el-button>
    </common-form>

    <script>
    data() {
    return {
    searchFrom: {
    keyword: ''
    },
    formLabel: [
    {
    model: 'keyword',
    label: '',
    type: 'input'
    }
    ]
    };
    }
    </script>

Table组件

简单使用

  • 看下element有关表格最简单的示例。Table 表格

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <template>
    <el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="日期" width="180"> </el-table-column>
    <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
    <el-table-column prop="address" label="地址"> </el-table-column>
    </el-table>
    </template>

    <script>
    export default {
    data() {
    return {
    tableData: [
    {
    date: "2017-05-04",
    name: "小小",
    address: "浙江省杭州市千岛湖镇 阳光路",
    },
    {
    date: "1956-05-04",
    name: "爷爷",
    address: "浙江省杭州市千岛湖镇 清波花园",
    },
    {
    date: "1958-05-04",
    name: "奶奶",
    address: "浙江省杭州市千岛湖镇 冬瓜乌",
    },
    ],
    };
    },
    };
    </script>

Pagination 分页

  • 当数据量过多时,使用分页分解数据。下面是一个完整

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     <div class="block">
    <span class="demonstration">完整功能</span>
    <el-pagination
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
    :current-page="currentPage4"
    :page-sizes="[100, 200, 300, 400]"
    :page-size="100"
    layout="total, sizes, prev, pager, next, jumper"
    :total="400">
    </el-pagination>
    </div>
    </template>
    <script>
    export default {
    methods: {
    handleSizeChange(val) {
    console.log(`每页 ${val} 条`);
    },
    handleCurrentChange(val) {
    console.log(`当前页: ${val}`);
    }
    },
    data() {
    return {
    currentPage4: 4
    };
    }
    }
    </script>

封装Table组件

  • 通过上面的示例,至少也是两份数据是需要父组件传入到表格组件中的:

    • v-model对应的数据,这份数据是用户选择好后给父组件的。
    • label 对应的数据,这里是写死的,既然要封装成一个控件那么这份数据也需要外面传过来。
  • 注意: 这里除了上面这两份数据外,还有一份数据在实际开发中也是需要的,那就是分页信息,因为一般table数据都会比较多所以分页还是非常需要的。

  • 新建一个CommonTable.vue,作为封装Table的组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    <template>
    <div class="common-table">
    <!--stripe 是否为斑马纹 v-loading在请求数据未返回的时间有个加载的图案,提高用户体验-->
    <el-table
    :data="tableData"
    height="90%"
    stripe
    v-loading="config.loading"
    >
    <!--第一行为序号 默认写死-->
    <el-table-column label="序号" width="85">
    <!--slot-scope="scope" 这里取到当前单元格,scope.$index就是索引 默认从0开始这里从1开始-->
    <template slot-scope="scope">
    <span style="margin-left: 10px">{{
    (config.page - 1) * 20 + scope.$index + 1
    }}</span>
    </template>
    </el-table-column>
    <!--show-overflow-tooltip 当内容过长被隐藏时显示 tooltip-->
    <el-table-column
    show-overflow-tooltip
    v-for="item in tableLabel"
    :key="item.prop"
    :label="item.label"
    :width="item.width ? item.width : 125"
    >
    <!--其实可以在上面:prop="item.prop"就可以显示表单数据 这里设置插槽的方式话更加灵活 我们可以写样式-->
    <template slot-scope="scope">
    <span style="margin-left: 10px">{{ scope.row[item.prop] }}</span>
    </template>
    </el-table-column>
    <!--操作-->
    <el-table-column label="操作" min-width="180">
    <template slot-scope="scope">
    <el-button size="min" @click="handleEdit(scope.row)"
    >编辑</el-button
    >
    <el-button size="min" type="danger" @click="handleDelete(scope.row)"
    >删除</el-button
    >
    </template>
    </el-table-column>
    </el-table>
    <!--分页-->
    <el-pagination
    class="pager"
    layout="prev, pager, next,total"
    :total="config.total"
    :current-page.sync="config.page"
    @current-change="changePage"
    :page-size="20"
    ></el-pagination>
    </div>
    </template>

    <script>
    // config分页数据,这里面至少包括当前页码 总数量
    export default {
    props: {
    tableData: Array,
    tableLabel: Array,
    config: Object,
    },
    methods: {
    //更新 调用父组件的 edit 方法
    handleEdit(row) {
    this.$emit("edit", row);
    },
    //删除 调用父组件的 del 方法
    handleDelete(row) {
    this.$emit("del", row);
    },
    //分页 调用父组件的 changePage 方法
    changePage(page) {
    this.$emit("changePage", page);
    },
    },
    };
    </script>
  • 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    <!--依次是: 表格数据 表格标签数据 分页数据  列表方法 更新方法 删除方法-->
    <common-table
    :tableData="tableData"
    :tableLabel="tableLabel"
    :config="config"
    @changePage="getList()"
    @edit="editUser"
    @del="delUser"
    >
    </common-table>

    <script>
    import CommonTable from "components/CommonTable";
    export default {
    data() {
    return {
    tableData: [
    {
    id: "e2de22E3-DbF4-E40C-abeF-e2ebcb74D8Df",
    name: "侯娜",
    addr: "四川省 阿坝藏族羌族自治州 金川县",
    age: 48,
    birth: "1997-09-03",
    sex: 0,
    sexLabel: "女",
    },
    {
    id: "dCfaae68-bEc3-Bc3D-aC91-cc738e31e6DE",
    name: "范洋",
    addr: "黑龙江省 齐齐哈尔市 昂昂溪区",
    age: 52,
    birth: "1999-05-13",
    sex: 1,
    sexLabel: "男",
    },
    {
    id: "eB9BAabF-516D-A8cb-Ff7b-E581a4C15CA3",
    name: "郝磊",
    addr: "甘肃省 定西市 临洮县",
    age: 26,
    birth: "1986-08-21",
    sex: 0,
    sexLabel: "女",
    },
    {
    id: "62f9b82e-698b-ea65-e3dC-a3f6CBC24faB",
    name: "顾秀英",
    addr: "台湾 新北市 瑞芳区",
    age: 53,
    birth: "2020-09-20",
    sex: 0,
    sexLabel: "女",
    },
    {
    id: "33b6b7fD-FEc4-d3c6-b1D2-5dB99F88E5b3",
    name: "张军",
    addr: "西藏自治区 拉萨市 尼木县",
    age: 31,
    birth: "2016-01-06",
    sex: 1,
    sexLabel: "男",
    },
    {
    id: "5188076A-C1fa-1e7E-f9cb-daBA0cccB868",
    name: "谭磊",
    addr: "青海省 海南藏族自治州 贵南县",
    age: 53,
    birth: "1996-08-11",
    sex: 1,
    sexLabel: "男",
    },
    {
    id: "DA914cCf-0CfE-25a1-e7BF-4A4A231Feb7F",
    name: "高洋",
    addr: "澳门特别行政区 离岛 -",
    age: 25,
    birth: "1995-06-21",
    sex: 0,
    sexLabel: "女",
    },
    {
    id: "9A46669B-962b-EedC-c8Db-Fb49C41E5f9E",
    name: "董杰",
    addr: "澳门特别行政区 澳门半岛 -",
    age: 46,
    birth: "2004-05-10",
    sex: 0,
    sexLabel: "女",
    },
    ],
    tableLabel: [
    { prop: "name", label: "姓名" },
    { prop: "age", label: "年龄" },
    { prop: "sexLabel", label: "性别" },
    { prop: "birth", label: "出生日期", width: 200 },
    { prop: "addr", label: "地址", width: 320 },
    ],
    config: {
    total: 8,
    loading: false,
    page: 1,
    pagesize: 20,
    },
    };
    },

    methods: {
    getList(name = "") {
    console.log("getList");
    },
    editUser(row = "") {
    console.log("editUser");
    },
    delUser(page = "") {
    console.log("delUser");
    },
    },
    };
    </script>
    <style lang="scss" scoped></style>