玩命加载中🤣🤣🤣

el-ui-primary


element-ui 笔记

快速搜索:

选择框的映射写法 >>> flag_1

表单重置 >>> flag_2

分页 >>> flag_3

时间框的解耦绑定 >>> flag_4

多标签页的切换与多接口调用 >>> flag_5

更新表单 >>> flag_6

新增表单 >>> flag_7

模板

Form 表单

<!-- 概念
  ref 绑定控件, 可通过$ref用于重置等操作; 
  :model 表单数据对象, 配合 el-form-item 的prop使用(:rule表单验证规则, 同理)
  :inline 如果不设置就会每一个item为一行
-->
<el-form ref="queryDto" :model="queryDto" :inline="true"  label-width="80px">
  <!-- 概念
    prop 绑定字段名, 从而实现表单校验, 即会验证 el-input 元素绑定的 queryDto.field 是否符合验证
  -->
  <el-form-item prop="inputField">
    <!-- 概念
  	  v-model 双向绑定; placeholder 占位提示
	-->
    <el-input v-model="queryDto.inputField" placeholder="字段1" size="mini" clearable />
  </el-form-item>
  <!-- 选择框: flag_1
    同时展示与字段处于映射关系写法
  -->
  <el-form-item prop="selectField">
    <el-select v-model="queryDto.selectField" placeholder="字段2" size="mini" clearable>
      <el-option v-for="item in queryDic._selectField" :key="item.id" :label="item.label" :value="item.value" />
    </el-select>
  </el-form-item>  
  <!-- 时间框: flag_4
    1. 绑定模型 v-model 因为生成的时间是数组形式, 为与dto解耦因此另外单独使用实体绑定, 因此后续重置表单要单独重置
    2. 粘贴快速选择项 :picker-options 注意这是模型data
    3. 全局搜索查询剩余要配置的部分
  -->
  <div class="block">
    <span>时间范围样式</span>
    <el-date-picker
      v-model="timeRange.timeField"
      type="daterange"
      size="mini"
      unlink-panels
      range-separator="至"
      start-placeholder="开始日期"
      end-placeholder="结束日期"
      :picker-options="pickerOptions"
    />
  <el-button size="mini" type="primary" value="search" @click="handleQuery()">查询</el-button>
  <!-- 重置: flag_2
    1. 绑定表单 resetForm('xxx')
    2. 粘贴方法 resetForm
    3. 注意: 如果有模型不在表单内需要额外清空(如本案例中的timeRange)
  -->
  <el-button size="mini" type="reset" @click="resetForm('queryDto')">重置</el-button>
  <el-button size="mini" type="primary" @click="handleInsert()">新增</el-button>
</el-form>
<!-- 
  分页: flag_3
  1. 绑定当前页 :current-page
  2. 设置分页选项: :page-sizes
  3. 绑定页总数: :total
  4. 粘贴方法:  @size-change, @current-change
-->
<div class="page">
  <el-pagination
    :current-page="queryDto.page"
    :page-sizes="[15, 25, 40, 50]"
    :page-size="100"
    layout="total, sizes, prev, pager, next, jumper"
    :total="respData.pager.total"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</div>
    
<script>
data(){
  return {
    queryDto: {
      inputField: '',
      // flag_1
      selectField: '',
      // 后端请求参数(具体根据接口文档需要) flag_4
      timeFieldStart: '',
      timeFieldEnd: '',
      // flag_3
      page: 1,
      size: 15
    },
    // 通过映射即可实现: 下拉框所展示与传给后端的值形成对应
    queryDic: {
      // flag_1
      _selectField: [
        { id: 0, value: 0, label: '映射1' },
        { id: 1, value: 1, label: '映射2' },
        { id: 2, value: 2, label: '映射3' }
      ]
	},
    // 时间范围字段(与dto进行解耦) flag_4
    timeRange: {
      timeField: ''
    },
    // 此处不关心返回数据的格式, 仅举例获取total
    respData: {
      list: [],
      // flag_3
      pager: {
        total: 0  // 注意此处不能用 ''
      }
    },
    // 快速选择时间范围(注意此处是data()内不是methods) flag_4
    pickerOptions: {
      shortcuts: [{
        text: '最近一周',
        onClick(picker) {
          const end = new Date()
          const start = new Date()
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
          picker.$emit('pick', [start, end])
        }
      }, {
        text: '最近一个月',
        onClick(picker) {
          const end = new Date()
          const start = new Date()
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
          picker.$emit('pick', [start, end])
        }
      }, {
        text: '最近三个月',
        onClick(picker) {
          const end = new Date()
          const start = new Date()
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
          picker.$emit('pick', [start, end])
        }
      }]
    }
  }
},
methods: {
  handleQuery() {
    // 查询方法(此处后端因为定义的时间范围是start和end, 因此查询前要做封装) flag_4
    if(this.timeRange.timeField) {
      // 封装时间dto(方法见下面)
      const _timeRange = this.handleDateRange(this.timeRange.timeField)
      this.queryDto.timeFieldStart = _timeRange[0]
      this.queryDto.timeFieldEnd = _timeRange[1]
      // 开始查询
    }
  },
  // 处理日期格式(具体日期格式转换见 附:date-format.js) flag_4
  handleDateRange(dateRange) {
    if (dateRange) {
      return [formatDate(dateRange[0]), formatDate(dateRange[1])]
    } else {
      return ['', '']
    }
  },
  // 重置表单 flag_2
  resetForm(formName) {
    this.$refs[formName].resetFields()
    // 此处要把时间范围的字段单独重置 flag_4
    this.timeRange.timeField = ''
  },
  // 分页size/page变更 flag_3
  handleSizeChange(val) {
    this.queryDto.size = val
    this.handleQuery() // size变更后重新查询
  },
  handleCurrentChange(val) {
    this.queryDto.page = val
    this.handleQuery() // page变更后重新查询
  }
}
</script>
    
<style>
/* 附: 分页栏底部居中样式 */
.page {
  /*设置为Flexbox容器*/
  display: flex;
  /*垂直居中*/
  align-items: center;
  /*水平居中*/
  justify-content: center;
  position: absolute;
  width: 100%;
  bottom: 20px;
}
</style>

附: 时间格式化工具类 date-format.js

// 时间格式化工具类
export function formatDate(value, pattern) {
  const dt = new Date(value)
  if (pattern === 'yyyy-M-d') { // yyyy-M-d
    const year = dt.getFullYear()
    const month = dt.getMonth() + 1
    const date = dt.getDate()
    return `${year}-${month}-${date}`
  } else if (pattern === 'yyyy-M-d H:m:s') { // yyyy-M-d H:m:s
    const year = dt.getFullYear()
    const month = dt.getMonth() + 1
    const date = dt.getDate()
    const hour = dt.getHours()
    const minute = dt.getMinutes()
    const second = dt.getSeconds()
    return `${year}-${month}-${date} ${hour}:${minute}:${second}`
  } else if (pattern === 'yyyy-MM-dd') { // yyyy-MM-dd
    const year = dt.getFullYear()
    const month = (dt.getMonth() + 1).toString().padStart(2, '0')
    const date = dt.getDate().toString().padStart(2, '0')
    return `${year}-${month}-${date}`
  } else { // yyyy-MM-dd HH:mm:ss
    const year = dt.getFullYear()
    const month = (dt.getMonth() + 1).toString().padStart(2, '0')
    const date = dt.getDate().toString().padStart(2, '0')
    const hour = dt.getHours().toString().padStart(2, '0')
    const minute = dt.getMinutes().toString().padStart(2, '0')
    const second = dt.getSeconds().toString().padStart(2, '0')
    return `${year}-${month}-${date} ${hour}:${minute}:${second}`
  }
}

Table 表格/Tag 标签

<!-- 标签页(可选) 
  说明: 多标签可能会存在多个接口对应多个表单的情况, 因此handleSearch(查询)时可以根据表单名进行路由接口 flag_5
  handleClick 切换标签方法
  el-tab-pane 中 form1 表示当前表单唯一标识(重要)
-->
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
  <el-tab-pane label="表单一" name="form1">
    <div class="searchTable">
      <span>前置说明</span>
      <div class="remind">
      <span>说明文字</span>
      </div>
      <el-divider />
      <div class="cTable">
        <el-table
          v-loading="loading.xxx"
          element-loading-text="玩命加载中🤣🤣🤣"
          element-loading-spinner="el-icon-loading"
          element-loading-background="rgba(196, 196, 196, 0.8)"
          :data="respData.xxxInfo"
          border style="width: 100%" 
          :header-cell-style="{ background: '#f8f8f8', color: '#000' }"
        >
          <!-- 编号字段 -->
          <el-table-column label="编号" type="index" width="auto" />
          <!-- 普通字段 -->
          <el-table-column prop="field1" label="字段一" width="100" />
          <!-- 映射字段 -->
          <el-table-column prop="mappingField" label="映射字段" width="120">
            <template v-slot="item">
              <template v-if="item.row.mappingField === 1">
                <div>类型1</div>
              </template>
              <template v-if="item.row.mappingField === 2">
                <div>类型2</div>
              </template>
              <template v-if="item.row.mappingField === 3">
                <div>类型3</div>
              </template>
            </template>
        </el-table-column>
          <!-- 右侧 删除/修改(详细见动态表单) 按钮 -->
          <el-table-column fixed="right" label="操作" width="100px">
            <template v-slot="item">
              <el-button type="text" size="small" @click="handleUpdate(item.row)">修改</el-button>
              <el-button type="text" size="small" @click="handleDelete(item.row.id)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
  </el-tab-pane>
</el-tabs>

<script>
data() {
  return {
    formType: 'form1' // 当前表单类型 flag_5
    respData: {
        xxxInfo: []
    }  
  }
},
methods: {
  handlerSearch() {
    // 根据当前标签类型调取不同接口 flag_5
    if (this.formType === 'form1') {
      // 进行form1的接口请求
    }
  },
  // 切换标签 flag_5
  handleClick(tab, event) {
    this.formType = tab.name
  },
  // 执行删除
  async handleDelete(id) {
    try {
      await this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
      await deleteById(id)
      await this.all()
      this.$message({
        type: 'success',
        message: '删除成功'
      })
    } catch (e) {
      this.$message({
        type: 'info',
        message: '已取消删除'
      })
    }
  },
  // 封装弹框方法
  alertMsg(msg) {
    Message({
    message: msg,
    type: 'warning',
    duration: 5 * 1000
    })
  },
}
</script>

<style>
/* 附: 表格样式 */
.searchTable {
  width: 90%;
  margin: 30px auto;
}
/* 附: 说明狂 */
.remind {
  width: 100%;
  margin-top: 10px;
  box-sizing: border-box;
  border: 1px solid #d9d9d9;
  padding: 20px 40px;
}
/* 附: 此处与前置说明框保持间距 */
.cTable {
  margin-top: 20px;
}
</style>

el-dialog 对话框

<el-table>
  <el-table-column fixed="right" label="操作" width="100px">
    <template v-slot="item">
      <!-- 打开更新表单面板 flag_6 -->
      <el-button type="text" size="small" @click="handleUpdate(item.row)">修改</el-button>
      <el-button type="text" size="small" @click="handleDelete(item.row.id)">删除</el-button>
    </template>
  </el-table-column>
</el-table>

<!-- 更新表单: flag_6
  :visible.sync 绑定是否显示对象
  :model 绑定更新data对象
  confirmUpdate() 确认
  label-width 表单标签文字宽度
  label-position 表单控制文字位置, 但要先设置文字宽度
  注意: 此处 el-form-item 标签中没加prop属性, 因为不需要校验操作, 具体qi
-->
<el-dialog width="25%" :visible.sync="updateDialogVisible">
  <el-form ref="updateForm" :model="updateForm" label-width="80px" label-position="left">
    <el-form-item label="id">
      <el-input v-model="updateForm.id" size="mini" :readonly="true" style="width: auto" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" size="mini" style="width: auto" @click="confirmUpdate()">确定</el-button>
      <el-button type="primary" size="mini" style="width: auto" @click="cancelUpdate()">取消</el-button>
    </el-form-item>
  </el-form>
</el-dialog>

<!-- 新增表单: flag_7
  :visible.sync 绑定是否显示对象
  confirmInsert() 新增
  cancelInsert()  取消方法
-->
<el-dialog width="25%" :visible.sync="insertDialogVisible">
  <el-form ref="insertForm" :model="insertForm" label-width="80px">
    <el-form-item>
      <el-button type="primary" size="mini" style="width: auto" @click="confirmInsert()">确定</el-button>
      <el-button type="primary" size="mini" style="width: auto" @click="cancelInsert()">取消</el-button>
    </el-form-item>
  </el-form>
</el-dialog>

<script>
data() {
  return {
    // 更新相关模型 flag_6
    updateDialogVisible: false,
    updateForm: {
      id: 0 // 更新唯一键: 通常根据接口从行中所取
    },
    // 新增相关模型 flag_7
    insertDialogVisible: false,
    insertForm: {
      // 表单内容
    }
  }
},
methods: {    
  // 打开更新表单面板(回显) flag_6
  handleUpdate(row) {
    this.updateDialogVisible = true
    // 解构对象(此处是因为还有别的数据封装)
    const curUser = { ...row }
    curUser.roles = curUser.roles || []
    this.updateForm = curUser
  },
  // 取消更新 
  cancelUpdate() {
    this.updateDialogVisible = false
    this.$message({
      type: 'info', 
      message: '已取消'
    })
  },
  // 确认更新
  async confirmUpdate() {
    await update(this.updateForm, this.updateForm.id)  // 调取更新接口
    this.updateDialogVisible = false  // 面板关闭
    await this.handleSearch() // 查询
    this.$message({
      type: 'warning',
      message: '更新成功'
    })
  },
  // 打开新增面板 flag_7
  handleInsert() {
    this.insertDialogVisible = true
  },
  // 取消新增
  cancelInsert() {
    this.insertDialogVisible = false
    this.$message({
      type: 'info',
      message: '已取消'
    })
  },
  // 确认新增
  async confirmInsert() {
    await insert(this.insertForm) // 新增
    this.insertDialogVisible = false // 面板关闭
    await this.handleSearch() // 查询
    this.$message({
      type: 'warning',
      message: '新增成功'
    })
  }
}
</script>

动态渲染表格(imp)

思路

  1. 前置说明: 由于该接口是动态查询数据库接口, 会有sql注入等风险, 因此仅用于个人运维使用. 同时为了接口传参通用性, 在sql中存在 select 1, fieldxxx from tablexxx , 因此在前端提取字段时, 要先将 1 字段删去
  2. 前端调取接口, 先将 1 字段删去, 而后遍历数据, 封装字段名
  3. 动态渲染至 el-table

查询并处理表头方法

// methods
// 执行查询 👇
async handLeSelect() {
    // 查询之前要把动态表头置为空
    this.tableHead = []
    // 校验参数
    if (!this.selectData.table || this.selectData.field.length === 0) {
        this.$message.warning('请先选择表及字段再进行查询')
        return
    }
    // 执行查询
    // 赋值到data
    this.loading.select = true // loading
    const data = await handleSelect(this.selectData)
    this.loading.select = false // loading
    this.respData.msg = data.data.exceptionMsg
    const list = data.data.data
    // 遍历删除属性名是数字的
    list.forEach(item => {
        delete item[1]
    })
    if (list.length !== 0) {
        const keyArr = Object.keys(list[0])
        keyArr.map(key => this.tableHead.push({ key: key }))
    }
    this.respData.selectResult = list
}

// data() 👇
// 动态表头
tableHead: []

template渲染

<div class="searchTable">
  <!-- 此处因为
  -->
  <el-table
    v-loading="loading.select"
    element-loading-text="玩命加载中🤣🤣🤣"
    :data="respData.selectResult"
    border
    style="width: 100%"
    max-height="530px"
    :header-cell-style="{ background: '#f8f8f8', color: '#000' }"
  >
    <!--模板表格-->
    <el-table-column
      v-for="item in tableHead"
      :key="item.key"
      :label="item.key"
      :property="item.key"
      width="250"
    > 
      <template v-slot="scope">
         <!-- tooltip提示标签卡
	       注意: tooltip的content需要string, 因此 scope.row[scope.column.property] 拿到字段值之后要 toString()
	  	-->
		<el-tooltip
           :content="scope.row[scope.column.property] ? scope.row[scope.column.property].toString() : ''"
         >
           <!-- 表格一行显示 👇 copyCellData(复制表格方法)-->
           <div style="text-align: center" class="oneline">
             <!-- 复制按钮 -->
             <el-button
               type="text"
               icon="el-icon-copy-document"
               @click="copyCellData(scope.row[scope.column.property])"
             />
             {{ scope.row[scope.column.property] }}
           </div>
        </el-tooltip>
      </template>
    </el-table-column>
  </el-table>
</div>
<script>
// ...methods
copyCellData(text) {
  if (!text) {
    this.$message.warning('无内容')
    return
  }
  const textarea = document.createElement('textarea')
  textarea.value = text
  document.body.appendChild(textarea)
  textarea.select()
  document.execCommand('copy')
  document.body.removeChild(textarea)
  this.$message.success('复制成功')
},
</script>

<style scoped>
.searchTable {
  width: 90%;
  margin: auto auto;
}

.oneline {
  overflow: hidden;
  text-overflow: ellipsis;
  /* 将对象作为弹性伸缩盒子模型显示 */
  display: -webkit-box;
  /* 限制在一个块元素显示的文本的行数 */
  /* -webkit-line-clamp 其实是一个不规范属性,使用了WebKit的CSS扩展属性,该方法适用于WebKit浏览器及移动端;*/
  -webkit-line-clamp: 1;
  /* 设置或检索伸缩盒对象的子元素的排列方式 */
  -webkit-box-orient: vertical;
}
    
/* 深度选择器-此处是为了解决el-table表头无法复制问题 important */
::v-deep .el-table th.el-table__cell {
  user-select: initial;
}
</style>

表格选择事件

只需要在 el-table 中添加 @selection-change事件及新增一个选择列即可, 代码如下👇

<!--
  1. 添加@selection-change并绑定事件
  2. 新增列 <el-table-column type="selection" />
  3. methods及data()见下
  附: 加载属性的使用: 新增如下属性即可 
    v-loading="loading.child"  // 绑定的loading字段, 同时要在请求接口前打开, 完成请求后关闭
    element-loading-text="玩命加载中🤣🤣🤣"
    element-loading-spinner="el-icon-loading"  // 如果全页面加载则删去此行
    element-loading-background="rgba(196, 196, 196, 0.8)"  // 如果全页面加载则删去此行
-->
<el-table
  v-loading="loading.detail"
  element-loading-text="玩命加载中🤣🤣🤣"
  :data="xxx"
  border
  style="width: 100%"
  max-height="530px"
  :header-cell-style="{ background: '#f8f8f8', color: '#000' }"
  @selection-change="handleSelectionChange"
>
  <el-table-column type="selection" />
  <el-table-column prop="xxx" label="逻辑名称" width="200" />
</el-table>

<script>
// ...data()
// 选择列表
selectedRows: []
    
// ...methods
// 表格选择事件(配合<el-table-column type="selection" />使用)
handleSelectionChange(selection) {
  // 此处会将选中的row加入至数组
  this.selectedRows = selection
},
</script>

组件

父子组件的引用

  1. 子组件引用父组件内容

    1. 在父组件的子标签中通过:属性/方法名传递过来

    2. export 中通过 props 引用进来

    3. 然后即可使用

    <script>
    export default {
      name: 'Child',
      props: {
        // 子组件引用父组件对象(子组件是不建议修改父组件属性内容)
        dic: {
          type: Object,
          required: true
        },
        // 引用方法后即可调用该方法
        query: {
          required: true
        }
      }
    }
    </script>
  2. 父组件引用子组件内容

    1. import 中导入子组件,并可以取别名
    2. componetnt 中声明子组件
    3. template 中创建子组件标签, ref 为上一步的引用名, 如果需要将父组件的方法或者对象传递给子组件, 则定义 变量即可
    4. 在代码中使用子组件方法/变量,如:$refs.子组件引用名.方法名(参数)
    <script>
    // 导入子组件
    import Child from './components/Child.vue'
    export default {
        component: { Child },
        methods: {
          invokeChildComponent() {
            // 引用子组件方法
            this.$refs.child.xxxMethod()
          }
        }
    }
    </script>
    
    <template>
    <div>
      <!-- 传递给子组件对象/方法
      	   :dic :query 将父组件对象/方法传递给子组件, 子组件通过该名字进行引用
      -->
      <User ref="child" :dic="queryDic" :query="handleQuery" />
      <!--  引用子组件内容 -->
      <el-button type="text" size="small" @click="$refs.child.queryTbUserByGuid(row.toRowGuid)">
          {{ row.toRowGuid }}
      </el-button>
    </div>
    </template>

    $refs 是 Vue.js 提供的一个特殊属性,用于获取组件或元素的引用。在模板中,可以使用 ref 属性来为组件或元素设置引用,然后在组件实例中使用 $refs 来访问这个引用。

  3. demo

    <!--  填写账号密码的伪代码
      this.$refs.username.focus() 是一种操作 DOM 元素的方式,可以让我们在组件实例中访问元素的引用,并调用元素的方法或属性
    -->
    <template>
      <el-input ref="username" v-model="loginForm.username" :placeholder="$t('login.username')" ...省略/>
    </template>
    <script>
    mounted() {
      // 如果用户名和密码的输入框没值, 则自动聚焦
      if (this.loginForm.username === '') {
          this.$refs.username.focus()
      } else if (this.loginForm.password === '') {
          this.$refs.password.focus()
      }
    }
    </script>

子组件监听父组件内容,而不直接使用父组件(watch方式)

<script>
props: {
    parentValues: {
      type: Object,
      default: nul
    }
},
data() {
        localValues: {
            ...this.parentValues // 创建本地副本
        }
    }
},
watch: {
    values: {
      handler (newVal) {
        this.localValues = { ...newVal }
      },
      deep: true
    }
},
</script>

emit 的使用

emit 是用于子组件向父组件传递信息的一种机制。它允许子组件触发一个自定义事件,并可以附带传递数据给父组件。

使用方法

  1. 子组件中触发事件

    在子组件内部,使用 this.$emit 来触发一个事件。第一个参数是事件的名称,之后的参数是传递给父组件的数据

    // 子组件内
    this.$emit('eventName', data)
  2. 父组件监听事件:父组件可通过 v-on 来监听子组件发出的事件,并执行相应的处理函数

    <!-- 父组件模板 -->
    <ChildComponent @eventName="handleEvent" />
    // 父组件的方法
    methods: {
      handleEvent(data) {
        console.log('子组件传来的数据:', data);
      }
    }

demo

假设有一个简单的计数器应用,其中子组件负责显示计数和提供增加计数的按钮,而父组件需要知道当前的计算值。

  • 子组件(Counter.vue)

    <template>
      <div>
        <p>当前计数: {{ count }}</p>
        <button @click="increment">+1</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          count: 0
        };
      },
      methods: {
        increment() {
          this.count++;
          this.$emit('updateCount', this.count); // 触发 updateCount 事件并传递 count
        }
      }
    };
    </script>
  • 父组件

    <template>
      <div>
        <h1>总计数: {{ total }}</h1>
        <Counter @updateCount="updateTotal" />
      </div>
    </template>
    
    <script>
    import Counter from './Counter.vue';
    
    export default {
      components: { Counter },
      data() {
        return {
          total: 0
        };
      },
      methods: {
        updateTotal(count) {
          this.total = count;
        }
      }
    };
    </script>

当用户点击点击子组件的按钮时,increment 方法被调用,此时会更新子组件的 count 数据属性,并通过 $emit 发出 updateCount 事件,将新的计数值传递给父组件。父组件监听了这个事件,并在 updateTotal 方法中更新自己的 total 数据属性

自定义组件demo

以封装 Tooltip 为例

  1. 定义 Tooltip.vue

    <template>
      <el-tooltip :content="content" :effect="effect" :placement="placement">
        <slot />
      </el-tooltip>
    </template>
    
    <script>
    export default {
      name: 'Tooltip',
      props: {
        content: {
          type: String,
          required: true
        },
        // 封装默认参数
        effect: {
          type: String,
          default: 'dark'
        },
        placement: {
          type: String,
          default: 'top'
        }
      }
    }
    </script>
  2. 组件的引用

<template>
<div>
  <el-table>
    <el-table-column prop="content" label="企业简介" width="150">
      <template v-slot="{ row }">
        <el-tooltip :content="row.content">
          <div style="text-align: center" class="oneline">
            {{ shortConent(row.content) }}
          </div>
        </el-tooltip>
      </template>
    </el-table-column>    
  </el-table>
</div>
</template>

<style>
.oneline {
  overflow: hidden;
  text-overflow: ellipsis;
  /* 将对象作为弹性伸缩盒子模型显示 */
  display: -webkit-box;
  /* 限制在一个块元素显示的文本的行数 */
  /* -webkit-line-clamp 其实是一个不规范属性,使用了WebKit的CSS扩展属性,该方法适用于WebKit浏览器及移动端;*/
  -webkit-line-clamp: 1;
  /* 设置或检索伸缩盒对象的子元素的排列方式 */
  -webkit-box-orient: vertical;
}
</style>

链接标签的定义

<el-table-column prop="toRowGuid" label="toRowGuid" width="260">
    <!-- 1. 定义template, 解构当前行 -->
    <template v-slot="{ row }">
        <!-- 2. 调用方法 -->
        <el-button type="text" size="small" @click="$refs.user.queryTbUserByGuid(row.toRowGuid)">
            {{ row.toRowGuid }}
        </el-button>
    </template>
</el-table-column>

watch的使用

基本用法

data() {
  return {
    watchField: true
  } 
},
watch: {
  // 监听watchField对象, 如果新值发生了变化, 则执行一下逻辑
  watchField(newV, oldV) {
	console.log('message changed from', oldV, 'to', newV)
  }
}

深度监听

如果要监听的对象时嵌套对象,需要使用 deep 选项来深度监听对象的变化

watch: {
  'someObject.nestedProperty': {
    handler(newV, oldV) {
      console.log('Nested property changed')
    },
    deep: true
  }
}

立即执行

默认情况下,watch 回调只会在监听到变化后触发。如果希望在初始渲染时也执行一次回调,可以使用 immediate 选项

watch: {
  someProperty: {
    handler(newVal, oldVal) {
      console.log('someProperty changed');
    },
    immediate: true
  }
}

监听多个属性

如果想在一个 watcher 中监听多个属性,你可以传递一个数组作为第一个参数:

watch: {
  ['property1', 'property2'](newVal, oldVal) {
    console.log('Either property1 or property2 has changed');
  }
}

注:这种方式不能直接获取到具体哪个属性发生了变化以及它的新旧值,因为 newValoldVal 会是整个对象的最新和旧值。如果需要知道具体哪个属性变化了,需要分别设置 watcher 或者在组件内维护额外的状态来跟踪这些变化。

使用计算属性替代

有时,watch 可能不是最佳选择,尤其是当只需要基于某些数据的变化来计算新值时。在这种情况下,使用计算属性(computed properties)可能是更好的选择。计算属性会根据其依赖的数据自动更新,并且更加简洁高效。

computed: {
  computedMessage() {
    return this.message + ' (Computed)';
  }
}

其他框架积累

CryptoJS 的使用

  1. 安装、引用

    npm install --save crypto-js 
    import CryptoJS from 'crypto-js'
  2. 使用

    // AES ECB加密
    const content = '待加密内容'
    const key = CryptoJS.enc.Utf8.parse('key')
    const encrypted = CryptoJS.AES.encrypt(content, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    })
    const encContent = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
    
    // AES ECB解密
    const content = '待解密内容'
    const key = CryptoJS.enc.Utf8.parse('key')
    const decrypted = CryptoJS.AES.decrypt(
        { ciphertext: CryptoJS.enc.Base64.parse(content) },
        key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }
    )
    const decContent = decrypted.toString(CryptoJS.enc.Utf8)

xml提取

npm install xml2js --save

import { Parser } from 'xml2js'
const parser = new Parser({ explicitArray: false })  // 关闭底部数组解析

const detailXml = data.data.data.tableInfo // 待处理的xml字符串
// 解析xml至对象
parser.parseString(detailXml, (err, result) => {
  if (err) {
    console.error(err)
  } else {
    this.tableData = result.EcaTable
  }
})

文章作者: 👑Dee👑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 👑Dee👑 !
  目录