了解常见组件库及使用流程

目标

了解一些常见的Vue组件库

前端项目分类

移动端(h5页, 小程序)

PC端

常见的vue技术栈组件库

  • 移动端(Vant[1], Cube-UI[2],  NutUI[3] echarts[4])

  • PC端 ( element-ui[5], Ant Design of Vue[6], iView[7])

  • 小程序: uniapp[8]

组件库的基本使用流程

  1. 根据项目的实际情况,进行技术选型:用什么技术栈,用什么组件库

  2. 去对应的官方查文档

  3. 遇到困难时

    1. 在官网上找 常见问题(一般在网页的最底部)
      下图是element官网[9]上的截图

26466521f0c6a77931dde614be46c646.png
    1. 在社区/搜索引擎 找答案

    2. 去提issue[10]  ,面对面直接向组件的作者提问

    3. 改源码

小结

  • vue技术栈有很多的组件库(一般大厂才会维护组件库)

  • 组件库要分移动端和PC端

  • 学习组件库的基本方法是查文档,遇到困难时提 issue

哈哈,给大家推荐饿了么ui,一起来look look吧

Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库

官方地址:element.eleme.cn/#/zh-CN[11]

ElementPlus(适配Vue3.0的版本)官方地址: element-plus.org/#/zh-CN[12]

目标

用vue-cli脚手架工具创建项目,并在项目中引入elementUI组件库

思路

用vue create 命令创建项目;根据elementUI官网中的说明来安装和使用组件

用vue-cli创建vue项目

vue create

找一个合适的文件夹,打开cmd窗口,用vue create 创建项目

vue create element-demo
-------------------------------
? Please pick a preset:
> Default ([Vue 2] babel, eslint)
  Default (Vue 3 Preview) ([Vue 3] babel, eslint)
  Manually select features
复制代码

注意:

  1. vue create 命令会自动创建文件夹,这样就不需要我们手动创建了

  2. 选择Vue2 版本的默认配置

  3. 如果vue create 命令不能正常运行,要先安装脚手架工具, 对应的命令是: npm i -g @vue/cli

cd 项目名再启动

上一步的命令做了两件事:创建文件夹,把示例项目的代码下载到这个文件夹中,为了运行项目,我们还需要进入项目目录下,并运行命令。对应的命令是:

cd element-demo # 进入项目目录
npm run serve # 运行命令
复制代码
查看效果

http://localhost:8080[13]

把ElementUI添加到项目中

参考官网文档[14],按全局引入的方式,一共分成两步:

  1. 安装 elementUI

  2. 在项目的main.js中引入使用

在项目中安装elementUI[15]
npm i element-ui -S
复制代码

-S: 是--save的简写,表示 这个包是生产依赖, 表示项目上线也要使用这个包。

-S: 是可以省略不写的。

如果要安装开发依赖,则要加 -D。

main.js中引入并注册

官网参考[16]

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
复制代码

上面的写法是固定模式,可随时去官网查看。

使用elementUI组件

使用组件的基本思路是:在官网上进行 cv操作。这里找一个最简单的button组件[17]进行尝试使用。

app.vue

<template>
  <div id="app">
    <el-button>默认按钮</el-button>
    <el-button type="primary">主要按钮</el-button>
    <el-button type="success">成功按钮</el-button>
    <el-button type="info">信息按钮</el-button>
    <el-button type="warning">警告按钮</el-button>
    <el-button type="danger">危险按钮</el-button>
  </div>
</template>
复制代码

注意:

  1. 组件名前面有el这个关键字

  2. type属性决定了按钮的样式风格

效果预览

如果打开浏览器预览,没有效果,那么一切ok~

小结

  1. elementui是做PC项目的首选

  2. 组件库一般都会有配套使用教程,基本套路是:

    1. npm i 安装

    2. 在main.js中导入,并使用


我们即将要开的人资项目是基于elementUI重度使用的一套架构,我们把后台管理系统一类的项目中高频使用的组件依次学习一下,方便大家更容易的接受业务的顺利进行


table组件-基础使用

用表格来显示数据,是一PC后台管理系统中一个非常常见的需求。

目标

能通过分析官网中的代码,把表格数据(文本数据)展示出来

dcf5d27430a684b7870f5d52a647c9db.png

思路

从官网上cv代码到项目中 ;

学习相关属性的使用;

基础demo

复制官方demo[18]中的第一个基础demo,先把我们的组件跑起来运行

<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: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }]
    }
  }
}
</script>
复制代码

效果如下

49494c538d52161336dbb4a2edb0cbb9.png

学习组件的使用

数据源由table组件的data属性来指定(不需要我们自己用v-for指令来循环)

  1. 行(data),决定表格的数据。它是数组,数组中的每一个元素是一个对象,表示一行。

  2. 列,决定表格结构。列由el-table-column决定,下面有三个属性需要掌握

    • label:决定当前列显示出的标题

    • prop:决定当前列数据的来源。对于表格来说, 它的数据是一个数组,每一个元素是一个对象,这里的prop值就是这个对象中的属性名

prop="date"。这里的prop就是用来从每一个对象中取出属性名为date的 属性值。

    • width: 用来设置列的宽度。如果不设置,它会自适应。

小结

在el-table使用data属性

在el-table-item上使用prop属性

091bf140b43a9616fd5b5b0b8d5ef9b0.png

table组件-自定义列-插槽

场景

有时候我们的表格单元格中,不光想要渲染文本,可能会渲染一些自定义的内容:  图片,操作按钮

目标

掌握自定义列的用法,能在表格单元格中显示自定义的内容。

需求描述:我们想在最后一列渲染出一个删除按钮

5029fe0960ae998e551b131d9c7349ba.png

思路

官网:自定义列模板[19]

代码

我们需要在对应的列中,使用template标签包裹我们自定义渲染的内容,其实用的就是插槽的机制

// 省略其它....
<el-table-column label="操作" width="100">
    <template>
      <el-button size="small" type="danger">删除</el-button>
    </template>
</el-table-column>
复制代码

小结

要自定义内容:

  1. 删除prop属性

  2. 插槽

table组件-自定义列-作用域插槽

需求说明

后端返回的数据中,只有一个指代性别的编码,为了方便用户查看,需要我们把1转换成男,0转换成女。

0c31fab173fcc2293df646f3817d2246.png

数据如下:

tableData: [{
       date: '2016-05-02',
       name: '王小虎',
       address: '上海市普陀区金沙江路 1518 弄',
     gender: 0
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄',
        gender: 1
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄',
        gender: 1
      }]
复制代码

解决思路

用作用域插槽拿到数据(官网[20]),再使用函数做转换输出即可

<el-table-column label="性别">
  <!-- 
 1. slot-scope是固定写法
  2. scope理解为变量,并不一定需要固定这个名字,el-table-column组件会自动将渲染本行需要的数据
  传给scope,其中scope.row就表示当前行的数据,它对应数据源中的某个对象。这里的row是固定写法
  3. {{ 方法() }} 的作用是执行这个方法,将返回值显示在当前单元格中
  -->
    <template slot-scope="scope">
      {{ transGender(scope.row.gender) }}
    </template>
</el-table-column>

<script>
  export default {
      methods: {
        transGender(genderCode) {
          console.log(genderCode)
          const genderList = {
            1: '男',
            0: '女'
          }
          return genderList[genderCode]
        }
      }
  }
</script>
复制代码

通过 Scoped slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据

小结

  1. 场景:直接使用prop只能渲染文本,通过prop不能直接渲染的时,我们需要自定义内容渲染

  2. 机制:作用域插槽

dbb730d7d56cd3f14838981059e46198.png
  1. 如何拿当前行的完整对象数据? scope.row

table组件-自定义列-显示图片(练习)

目标

把图片显示在表格中

数据

tableData: [{
   companyName: '小米',
   companyLogo: 'http://s02.mifile.cn/assets/static/image/logo-mi2.png'
 }, 
 {
    companyName: '京东',
    companyLogo: 'https://misc.360buyimg.com/lib/img/e/logo-201305-b.png'
  }, 
  {
    companyName: '百度',
    companyLogo: 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
  }
]
复制代码

代码

<template>
  <div>
    <el-table :data="tableData">
      <el-table-column
        label="公司名"
        prop="companyName">
      </el-table-column>

      <el-table-column
        label="公司logo"
        prop="companyLogo">
      </el-table-column>

      <el-table-column
        label="公司logo"
        >
        <!-- 
          slot-scope: 是老语法,
          v-slot :是新语法。效果一样
        -->
      <template slot-scope="scope">
        <!-- {{scope.row.companyLogo}} -->
        <img :src="scope.row.companyLogo"/>
      </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data () {
    return {
      tableData: [{
        companyName: '小米',
        companyLogo: "http://s02.mifile.cn/assets/static/image/logo-mi2.png"
      }, 
      {
          companyName: '京东',
          companyLogo:"https://misc.360buyimg.com/lib/img/e/logo-201305-b.png"
        }, 
        {
          companyName: '百度',
          companyLogo:"https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
        }
      ]
    }
  }
}
</script>
复制代码

pagination-翻页组件

分页组件的官网地址:element.eleme.cn/#/zh-CN/com…[21]

目标

掌握翻页组件的使用

基础使用

<el-pagination 
  layout="prev, pager, next" 
  :total="1000">
</el-pagination>
复制代码

说明:

  • layout中的关键字有自己的含义;

  • total用来设置数据的总条数

每页条数

page-size:默认每页10条数据

翻页事件

当用户点击页面进行翻页时就会触发current-change 事件

<template>
  <div>
    <h1>Pagination</h1>
    <el-pagination
      layout="prev, pager, next"
      :total="1000"
      @current-change="pageChange"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  methods: {
    // 把当前点击的页数给传进来
    pageChange(page) {
      console.log(page)
    }
  }
}
</script>
复制代码

注意:

  1. 事件名不是驼峰命名法,而是采用kebab-case(昵称:烤串命名法)

  2. 它会自动接收页码

小结

  1. 翻页按钮的结构 :layout 按照我们传入的结构顺序依次渲染

  2. 分页逻辑:总页数 = 总条数(:total) / 每页的条数(:page-size)

  3. 事件: \@current-change[22]

  4. 翻页组件一般和表格一起使用,但是,它并不决定表格的数据来源。

Form表单组件-基本使用

目标

掌握表单组件的基本使用

思路

在官网上cv一个最复杂的例子,然后对应做修改

用户登录表单-数据双向绑定

<template>
  <div class="form-container">
    <el-form label-width="80px">
      <el-form-item label="手机号">
        <el-input v-model="form.mobile"></el-input>
      </el-form-item>
      <el-form-item label="密码">
        <el-input v-model="form.code"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">立即创建</el-button>
        <el-button>取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      form: {
        mobile: '',
        code: ''
      }
    }
  },
  methods: {
    onSubmit() {
      console.log('submit!')
    }
  }
}
</script>

<style scoped>
  .form-container{
    width: 600px;
  }
</style>
复制代码

小结

  • 表单中的数据项一般会用一个对象包起来

  • 属性名一般和后端接口中保持一致

  • 在元素上采用v-model双向绑定

Form表单校验-基本介绍

目标

了解表单校验的必要性和实现方式

校验必要性

在向后端发请求调用接口之前,我们需要对所要传递的参数进行验证,来把用户的错误扼杀在摇篮之中。

不能相信用户的任何输入!不能相信用户的任何输入!不能相信用户的任何输入!

校验内容

  • 内容不能为空(*)

  • 密码长度必须多少位

  • 手机号的格式要合规

  • 邮箱的格式要合规

  • ...

校验方式

  • 不依赖于任何组件的验证

    • 在做提交之前,自己把数据分析处理一下。

  • 基于具体组件的验证(不同的组件库,它的验证方式可能也各有不同)

小结

  • 表单内容一定要验证(不能相信用户的任何输入!);

  • 如果使用是组件库中的表单,最好是采用它们自带的验证方式

Form表单组件-表单验证

场景

在上面的表单中,要求:用户名必填

目标

掌握element-ui中表单校验的使用

基本步骤-共三步

  1. 定义验证规则。data()中按格式定义规则

  2. 在模板上做属性配置来应用规则(三个配置)
    给表单设置 rules 属性传入验证规则
    给表单设置model属性传入表单数据
    给表单项(Form-Item )设置 prop 属性,其值为设置为需校验的字段名

  3. 手动兜底验证

步骤1-定义表单验证规则

在 data 中,补充定义规则。

格式:

data() {
  return {
    rules: {
        // 字段名1:表示要验证的属性
        // 值: 表示验证规则列表。它是一个数组,数组中的每一项表示一条规则。
        //     数组中的多条规则会按顺序进行
        字段名1: [
          { 验证规则1 },
          { 验证规则2 },
        ],
        字段名2: [
          { 验证规则1 },
          { 验证规则2 },
        ], 
  }
  }
}
复制代码

示例

{ required: true, message: '请输入验证码', trigger: 'blur' },
  { pattern: /^\d{6}$/, message: '请输入合法的验证码', trigger: 'blur' },
  { min: 6, max: 8, message: '长度为6-8位', trigger: 'blur' }
复制代码

实操代码

data () {
    return {
      // 表单验证规则,整体是一个对象
      // 键:要验证的字段, 值:是一个数组,每一项就是一条规则
      
      rules: {
        // 字段名:mobile就表示要验证的 属性
        // 值: 是一个数组。数组中的每一项表示一条规则。
        mobile: [
          { required: true, message: '请输入手机号', trigger: 'blur' }
        ]
      }
    }
  },
复制代码

注意:

  • rules中的属性名与表单数据项中的属性名必须是一致的。

步骤2-模板中的配置

内容:

  1. 给 el-form 组件绑定 model 为表单数据对象

  2. 给 el-form 组件绑定 rules 属性配置验证规则

  3. 给需要验证的表单项 el-form-item 绑定 prop 属性,注意:prop 属性需要指定表单对象中的数据名称

代码:

<el-form label-width="80px" :model="form" :rules="rules">
  <el-form-item label="手机号" prop="mobile">
    <el-input v-model="form.mobile"></el-input>
  </el-form-item>
  <el-form-item label="密码" prop="code">
    <el-input v-model="form.code"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button @click="onCancel">取消</el-button>
  </el-form-item>
</el-form>
复制代码

验收效果

我们做到这一步时,当用户输入的内容不符合表单规则要求时,并且某个输入框失焦时,它会给出相应的提示,当我们输入的内容符合要求时,错误提示会自动消失。

步骤3-手动兜底验证

格式

element-ui的表单组件.validate(valid => {
 if(valid) {
    // 通过了验证
 } else {
   // 验证失败
 }
})
复制代码

说明:

  • validate[23] 方法是表单组件自带的,用来对表单内容进行检验。

  • 需要在模板中添加对表单组件的引用:ref 的作用主要用来获取表单组件手动触发验证

代码-模板

<el-form label-width="80px" 
+  ref="form"
   :model="form"
   :rules="rules">
复制代码

添加ref来引用el-form组件。

代码

在做提交时进行手动兜底验证,如果通过了验证

doLogin () {
  alert('我可以做登录了')
},
submit () {
  this.$refs.form.validate(valid => {
    // valid 就是表单验证的结果,如果是true,表示通过了
    // console.log(valid)
    if (valid) {
      // 通过了验证,你可以做后续动作了
      this.doLogin()
    }
  })
}
复制代码

小结

步骤

  1. 定义验证规则(按element-ui的要求来)

  2. 配置模板,应用规则
    给表单设置 rules 属性传入验证规
    给表单设置model属性传入表单数据
    给表单中的元素(Form-Item )设置 prop 属性,其值为设置为需校验的字段名

  3. 手动兜底验证

Form表单组件-表单验证-作业

在我们上一节课的基础上来做。

目标

  1. 手机号/用户名不能为空,且必须为11位手机号 (/^1[0-9]{10}$/)

  2. 密码为必填且长度6到8位字符

代码

定义规则

rules:{
          name: [
            // trigger: 什么时候触发验证 
            { required: true, message: '请输入手机号', trigger: 'blur' },
            // pattern : 正则
            { pattern: /^1[345678]\d{9}$/, message: '请输入合法的手机号', trigger: 'blur' }
          ],
          password: [
            { required: true, message: '请输入手机号', trigger: 'blur' },
            { min: 6, max: 8, message: '长度为6-8位', trigger: 'blur' }
          ]
        }
复制代码

模板中配置应用规则

<el-form ref="form" :model="form" :rules="rules" label-width="80px">
    <el-form-item label="手机号" prop="name">
      <el-input v-model="form.name"></el-input>
    </el-form-item>

    <el-form-item label="密码" prop="password">
      <el-input v-model="form.password"></el-input>
    </el-form-item>
    
    <el-form-item>
      <el-button type="primary" @click="onSubmit">立即创建</el-button>
      <el-button>取消</el-button>
    </el-form-item>
  </el-form>
复制代码

注意

下面三个地方的属性名必须一致

315071916619598c824bda357bb4f614.png

Form表单组件-表单验证-自定义检验规则

场景:

密码不允许是123456

目标

掌握自定义检验规则的使用格式

思路

在rules中自定义validator

格式

rules:{
    属性名1: [
      
      { 
        // 注意参数顺序
        validator: function (rule, value, callback) {
        // rule:采用的规则
          // value: 被校验的值
          // callback是回调函数, 
          //      如果通过了规则检验,就直接调用callback()
          //      如果没有通过规则检验,就调用callback(错误对象,在错误对象中说明原因)
         //         例如:callback(new Error('错误说明'))
       }, 
        trigger: 'blur' 
     }
    ]
}
复制代码

落地代码

rules: {
  name: [{required: true, message:'必须要填入', triggle: 'blur'}],
  code: [
      {
        validator:(rule, value, callback)=>{
          console.log(rule, value, callback)
          if(value === '123456') {
            callback(new Error('这是世界上最差的密码了'))
          } else {
            callback()
          }
       },
        triggle: 'blur'
      },
      {min: 6, max:8, message:'长度为6-8位', triggle: 'blur'},
      {required: true, message:'必须要填入', triggle: 'blur'},
  ]
}
复制代码

小结

  • 自定义规则可以让校验逻辑更加灵活,它的格式是固定的

  • callback必须调用

Form表单组件-重置表单清理校验痕迹

背景

校验失败会有红色的提示文字,有时候我们需要在执行了某个操作之后把当前校校验失败留下的痕迹清理一下,为下一次校验做准备。

格式

this.$refs.form组件的引用.resetFields()
复制代码

这个方法可以

  1. 清理校验痕迹

  2. 恢复表单默认数据

Tree树形组件

目标

了解树状结构的数据;

学习Tree组件的基础使用

78ff69e1b5b7542ef46d1272ab6b866e.png

什么是树形数据

有一些业务场景在描述主体关系的时候必须使用树形数据,比如:我们常见的家庭成员关系图,公司里的组织架构等,要描述这样的业务场景,与之对应的,我们就得给出树形结构的数据

0a1022306535da85f5fd84051fad2574.png

Tree组件基础使用

学习树状结构的数据和label、children属性

示例代码[24]

<template>
  <el-tree :data="data"></el-tree>
</template>

<script>
export default {
  data() {
    return {
      data: [{
        label: '一级 1',
        children: [{
          label: '二级 1-1',
          children: [{
            label: '三级 1-1-1'
          }]
        }]
      }, {
        label: '一级 2',
        children: [{
          label: '二级 2-1',
          children: [{
            label: '三级 2-1-1'
          }]
        }, {
          label: '二级 2-2',
          children: [{
            label: '三级 2-2-1'
          }]
        }]
      }, {
        label: '一级 3',
        children: [{
          label: '二级 3-1',
          children: [{
            label: '三级 3-1-1'
          }]
        }, {
          label: '二级 3-2',
          children: [{
            label: '三级 3-2-1'
          }]
        }]
      }]
    }
  }
}
</script>
复制代码

上面我们就完成了一个基础树形组件的渲染,依赖一个data属性即可,data属性传入的就是树状结构

注意:

  • 数据项中label和children是关键字,不可随意改动。tree组件用它们来显示内容

配置自定义渲染字段

tree组件渲染节点title默认使用的是数据中的label属性,识别子节点默认使用的是children属性,我们尝试把data里的属性名换一下,例如:label换成name,children换成childList,就会发现渲染失败了。

如果你非要去自定义这个两个关键字:label和children的话,就需要用到props属性了。

如下:

<el-tree :data="data" :props="defaultProps"></el-tree>

defaultProps:{
    label:'name',
    children:'childList'
}
复制代码

获取特定树形节点数据

当我们点击某个树形子节点的时候,如何获取到当前点击这项节点对应的数据?

监听时间:@node-click="handleNodeClick"`

<template>
  <el-tree :data="data" @node-click="handleNodeClick"></el-tree>
</template>

<script>
  export default {
     methods:{
       // 共三个参数,
       // 依次为:
       //   - 传递给 data 属性的数组中该节点所对应的对象
       //   - 节点对应的 Node
       //   - 节点组件本身
        handleNodeClick(a,b,c){
          console.log(a,b,c)
        }
      }
  }
</script>
复制代码

小结

  1. 使用场景:组织架构   人员关系
  2. 树形数据
data:[
  {
    label:'a',
    id:101,
    children:[
        {},
        {},
        {}
    ]
  }
]
复制代码
  1. 自定义props适配数据渲染字段

Tree树形组件-练习题

将下图中的数据内部用树形数据表示出来,并通过tree显示

78df80c67a86d5a47921a7b7cfede7cd.png

参考代码

data: [{
        label: '张大大',
        children: [
          {
           label: '小亮',
           children: [{label: '小丽'},{label: '大光'}]
         },
          {
           label: '小美',
           children: [{label: '小高'}]
         },
          {
           label: '老马',
           children: [{label: '小刘'},{label: '小华'},{label: '小李'}]
         },
          {
           label: '老王',
           children: [{label: '小赵'},{label: '小强'}]
         },
          {
           label: '老李',
           children: [{label: '小涛'}]
         }
       ]
      }]
复制代码

思考题:数组转化成树(难点-难点-难点)

背景

后端接口返回的数据一般是平铺的数组结构,而不会是树形结构,例如下面的平铺数组结构:

data = 
[
  {id:"01", name: "张大大", pid:"", job: "项目经理"},
  {id:"02", name: "小亮", pid:"01", job: "产品leader"},
  {id:"03", name: "小美", pid:"01", job: "UIleader"},
  {id:"04", name: "老马", pid:"01", job: "技术leader"},
  {id:"05", name: "老王", pid:"01", job: "测试leader"},
  {id:"06", name: "老李", pid:"01", job: "运维leader"},
  {id:"07", name: "小丽", pid:"02", job: "产品经理"},
  {id:"08", name: "大光", pid:"02", job: "产品经理"},
  {id:"09", name: "小高", pid:"03", job: "UI设计师"},
  {id:"10", name: "小刘", pid:"04", job: "前端工程师"},
  {id:"11", name: "小华", pid:"04", job: "后端工程师"},
  {id:"12", name: "小李", pid:"04", job: "后端工程师"},
  {id:"13", name: "小赵", pid:"05", job: "测试工程师"},
  {id:"14", name: "小强", pid:"05", job: "测试工程师"},
  {id:"15", name: "小涛", pid:"06", job: "运维工程师"}
]
复制代码

这样的数据可以直接在table中使用,但是不能直接在tree组件中使用,需要我们做一些转换。

额外补充一个函数来做转换

代码

const data = [
  {id:"01", name: "张大大", pid:"", job: "项目经理"},
  {id:"02", name: "小亮", pid:"01", job: "产品leader"},
  {id:"03", name: "小美", pid:"01", job: "UIleader"},
  {id:"04", name: "老马", pid:"01", job: "技术leader"},
  {id:"05", name: "老王", pid:"01", job: "测试leader"},
  {id:"06", name: "老李", pid:"01", job: "运维leader"},
  {id:"07", name: "小丽", pid:"02", job: "产品经理"},
  {id:"08", name: "大光", pid:"02", job: "产品经理"},
  {id:"09", name: "小高", pid:"03", job: "UI设计师"},
  {id:"10", name: "小刘", pid:"04", job: "前端工程师"},
  {id:"11", name: "小华", pid:"04", job: "后端工程师"},
  {id:"12", name: "小李", pid:"04", job: "后端工程师"},
  {id:"13", name: "小赵", pid:"05", job: "测试工程师"},
  {id:"14", name: "小强", pid:"05", job: "测试工程师"},
  {id:"15", name: "小涛", pid:"06", job: "运维工程师"}
]

// 完成代码
function arrToTree(data) {
  
  // 你的代码
  
}

// 目标:
const treeData = arrToTree(data)
// treeData就是:
// [{
//   label: '张大大',
//   children: [
//     {
//       label: '小亮',
//       children: [{label: '小丽'},{label: '大光'}]
//     },
//     {
//       label: '小美',
//       children: [{label: '小高'}]
//     },
//     {
//       label: '老马',
//       children: [{label: '小刘'},{label: '小华'},{label: '小李'}]
//     },
//     {
//       label: '老王',
//       children: [{label: '小赵'},{label: '小强'}]
//     },
//     {
//       label: '老李',
//       children: [{label: '小涛'}]
//     }
//   ]
// }]
复制代码

在网上看了很多答案,自己验证过以后,这个是我觉得最优的一个,供参考

function tranListToTreeData(list) {
      // 1. 定义两个中间变量
      const treeList = [],  // 最终要产出的树状数据的数组
        map = {}        // 存储映射关系

      // 2. 建立一个映射关系,并给每个元素补充children属性.
      // 映射关系: 目的是让我们能通过id快速找到对应的元素
      // 补充children:让后边的计算更方便
      list.forEach(item => {
        if (!item.children) {
          item.children = []
        }
        map[item.id] = item
      })

      // 3. 循环
      list.forEach(item => {
        // 对于每一个元素来说,先找它的上级
        //    如果能找到,说明它有上级,则要把它添加到上级的children中去
        //    如果找不到,说明它没有上级,直接添加到 treeList
        const parent = map[item.pid]
        // 如果存在则表示item不是最顶层的数据
        if (parent) {
          parent.children.push(item)
        } else {
          // 如果不存在 则是顶层数据
          treeList.push(item)
        }
      })
      // 4. 返回出去
      return treeList
    }

复制代码

Dialog弹框组件

目标

学习Dialog弹框组件的基础使用

弹框组件基础使用

  • 基本交互

  • 使用默认插槽来自定义内容

<template>
  <div>
    <el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
    <el-dialog
      title="提示"
      :visible.sync="dialogVisible"
      width="30%"
    >
      <span>这是一段信息</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        dialogVisible: false
      }
    }
  }
</script>
复制代码

监听open和close事件

弹框组件有俩种状态,一个是打开一个是关闭,如果我们想在它打开或者关闭时做一些自己的事情,就可以监听俩个事件

\@close[25]  弹框关闭 : dialogVisible从true变成false

\@open[26]  弹框打开 : dialogVisible从false变成true

<template>
  <div>
    <el-button type="text" @click="dialogVisible = true"
      >点击打开 Dialog</el-button
    >
    <el-dialog
      title="提示"
      :visible.sync="dialogVisible"
      @close="dialogClose"
      @open="dialogOpen"
      width="30%"
    >
      <span>这是一段信息</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false,
    }
  },
  methods: {
    dialogClose() {
      console.log('弹框要关闭了')
    },
    dialogOpen(){
      console.log('弹框打开咯')
    }
  }
}
</script>
复制代码

取消两种关闭的方式

<el-dialog
      :close-on-click-modal="false"
      :close-on-press-escape="false"
复制代码

小结

  1. 弹框组件一共俩种状态  打开和关闭  :visible.sync="布尔值"

  2. open和close俩个自定义事件要关注

  3. 取消两种关闭的方式(点击遮罩,esc)

MessageBox

openMessage () {
      this.$message({
        type: 'success ',
        message: `月薪15K`
      })
    },
    open () {
      this.$alert('你真的要走吗?', '系统提示', {
        confirmButtonText: '确认',
        callback: action => {
          this.$message({
            type: 'info',
            message: `action: ${action}`
          })
        }
      })
    }
复制代码

Select

基本使用

<template>
  <el-select v-model="value" placeholder="请选择">

    <!-- label: 显示的内容
    value: 选中之后要保存的内容---值 -->
    <el-option
      v-for="item in options"
      :key="item.value"

      :label="item.label"
      :value="item.value">
    </el-option>

  </el-select>
</template>

<script>
export default {
  data () {
    return {
      options: [{
        value: '1',
        label: '黄金糕'
      }, {
        value: '2',
        label: '双皮奶'
      }, {
        value: '选项3',
        label: '蚵仔煎'
      }, {
        value: '选项4',
        label: '龙须面'
      }, {
        value: '选项5',
        label: '北京烤鸭'
      }],
      value: ''
    }
  }
}
</script>
复制代码

多个的select联动

selecct:  @change, ajax

Tabs

用来做页面布局

案例-整体介绍

目标

复习vue项目中路由的使用(嵌套路由);

了解后台管理系统的基本页面结构

基本内容

bb8915185a1114771e97b3be765c5233.png

需求描述:

  1. 登录页实现表单校验功能,校验通过之后跳转到首页

  2. 首页默认进入到table菜单路由下,表格渲染列表

  3. 表格数据里的性别 1 转换成 男  0转换成 女

案例-引入路由

在当前的项目中,我们并没有引入vue-router,所以我们这里先来单独安装一下它。

安装

npm i vue-router

复习使用vue-router的基本步骤

  • 定义路由并导出

  • 在main.js中导入,并挂载到vue实例中

  • 设置路由出口

定义

src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/login.vue'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    { path: '/login', component: Login }
  ]
})

export default router
复制代码

使用

src/main.js中引入

// 省略其他
import router from '@/router/index.js'

new Vue({
+ router,
  render: h => h(App),
}).$mount('#app')
复制代码

app.vue中定义路由出口

src/app.vue

<div id="app">
    <router-view></router-view>
  </div>
复制代码

案例-Login模块实现

Login静态布局页面

src/views/login.vue

<template>
  <div class="login-container">
    <div class="form-container">
      <el-form label-width="80px">
        <el-form-item label="手机号:">
          <el-input v-model="form.mobile"></el-input>
        </el-form-item>
        <el-form-item label="密码:">
          <el-input v-model="form.password"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary">确定</el-button>
          <el-button>取消</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div>自行完成表单验证</div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      form: {
        mobile: '',
        password: ''
      }
    }
  }
}
</script>

<style scoped>
.login-container {
  width: 100vw;
  height: 100vh;
  background-color: rgb(238, 241, 246);
}
.form-container {
  width: 500px;
  height: 400px;
  border: 1px solid #b3c0d1;
  border-radius: 10px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  justify-content: center;
  align-items: center;
  }
</style>
复制代码

案例-用container和menu实现主页

分析

需要有单独的组件来做主页布局

ce6556a14de73b9d5e1687fed0147c27.png

Layout静态布局

src/views/layout.vue

container组件布局[27]  menu组件[28]

<template>
  <el-container style="height: 100vh">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <div class="logo">实战案例logo</div>
      <!-- 菜单区域 -->
      <el-menu>
        <el-menu-item index="1-1">table</el-menu-item>
      </el-menu>
    </el-aside>
    <el-container>
      <el-header style="text-align: right; font-size: 12px">
        <i class="el-icon-setting" style="margin-right: 15px"></i>
        <span>王小虎</span>
      </el-header>
      <el-main>
        这里是主体
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {}
</script>
<style>
.logo{
  height: 60px;
  text-align: center;
  line-height: 60px;
  color:#333;
  text-shadow: 0 0 4px #b3c0d1;
  font-size: 20px;
}
.el-header {
  background-color: #b3c0d1;
  color: #333;
  line-height: 60px;
}
.el-aside {
  color: #333;
}
</style>
复制代码

路由配置

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/login.vue'
import Layout from '@/views/layout.vue'
Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/login',
      component: Login
    },
    {
      path: '/', // 主页
      component: Layout
    }
  ]
})

export default router
复制代码

验收效果

通过路由地址访问一下,看看是否能显示主页

案例-配置二级路由

目标

src/views/layout.vue

<el-container>
  <el-header>Header</el-header>
  <el-main>
    <!-- 二级路由出口 -->
    <router-view />
  </el-main>
</el-container>
复制代码

导航菜单

src/views/layout.vue 中,设置index和router

<el-menu
          default-active="/"
          class="el-menu-vertical-demo"
          router
        >
          <el-menu-item index="/">
            <i class="el-icon-menu"></i>
            <span slot="title">主页</span>
          </el-menu-item>
         
          <el-menu-item index="/tree">
            <i class="el-icon-setting"></i>
            <span slot="title">树</span>
          </el-menu-item>
        </el-menu>
复制代码

rotuer: 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转

Table模块实现

table静态布局

<template>
  <div class="table-container">
    <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>
    <div class="page">
      <el-pagination layout="prev, pager, next" :total="50"> </el-pagination>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }]
    }
  }
}
</script>

<style lang="less" scoped>
 .page{
   margin-top: 20px;
 }
</style>
复制代码

BUG修复

描述:

选中其他的菜单,刷新页面,发现默认选中的菜单不对!

解决

:default-active="$route.path"

关于本文

来自:sunshine_

https://juejin.cn/post/7097558307568615454

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿

回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!

回复「交流」,吹吹水、聊聊技术、吐吐槽!

回复「阅读」,每日刷刷高质量好文!

如果这篇文章对你有帮助,「在看」是最大的支持

 》》面试官也在看的算法资料《《

“在看和转发”就是最大的支持

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐