前端开发小技巧

171 阅读1分钟

Vue

1、vue中@click.native的使用

组件中时常看到@click.native。在项目中遇到后,简单介绍下:

@click.native是给vue组件绑定原生事件

  • 1、给vue组件绑定事件时候,必须加上native ,否则会认为监听的是来自Item组件自定义的事件
  • 2、等同于在子组件中: 子组件内部处理click事件然后向外发送click事件:$emit("click".fn)

image.png

如果是组件绑定键盘事件:

如给el-input绑定回车触发事件 @keyup.enter.native=
给普通div绑定回车事件  @keyup.enter =""

2、.sync修饰符

我们常见的父与子组件之间的通信,一般都是父组件自定义属性,子组件通过子props接收,如果想修改父组件传递过来的变量,一般使用this.$emit(事件名,参数,…)的形式进行事件提交.sync是vue中用于实现简单的“双向绑定”的语法糖.

  • .sync修饰符之前的写法

父组件:

<parent :myMessage=“bar” @update:myMessage=“func”>

func(val){
	this.bar = val;
}

子组件中的事件触发函数:

func2(){
	this.$emit(‘update:myMessage’,valc);
}
  • 使用.sync修饰符的写法

会简化上面的写法,父组件不需要定义更新触发函数。
父组件:

<comp :myMessage.sync="bar"></comp>

子组件:

this.$emit('update:myMessage',valc);

3、el-table-column 使用 v-if 做动态列效果导致的顺序错乱处理

场景描述

点击不同的按钮之后,就会切换不同的table表格,这两个表格的列表字段是不同的

  • 人工智能榜的表头

image.png

  • 企业百强榜的表头

image.png

错误代码展示

使用饿了么的el-table表格,将相应的表头字段分为两组,使用v-if去控制是否展示

image.png

实际效果

点击企业百强榜后,表头的顺序错乱

  • 正确的表头字段排序应该是 企业名称 => 企业详情 => 状态

image.png

解决方法

使用 v-if 后,可能与 vue 的渲染机制有关,导致排序混乱;每一个 el-table-column 都加上一个固定的key值,即可解决问题

image.png

具体的案列代码

<template>
  <div class="table">
    <div class="tab-item-main">
      <div class="tab-item"
        :class="{ 'tab-item-click': tabIndex == item.id }"
        v-for="(item,index) in enterprisesTab" :key="index"
        @click="changeIndex(item.id)">
        <div class="tab-item-text">
          {{item.name}}
        </div>
      </div>
    </div>
    <div>
      <el-table :data="tableList" style="width: 100%" border>
        <!-- 人工智能榜 -->
        <template v-if="tabIndex == 1">
          <el-table-column key="1" prop="name" label="名称">
          </el-table-column>
          <el-table-column key="2" prop="detail" label="详情">
          </el-table-column>
          <el-table-column key="3" prop="status" label="状态">
          </el-table-column>
        </template>

        <!-- 企业百强榜 -->
        <template v-if="tabIndex == 2">
          <el-table-column key="4" prop="name" label="企业名称">
          </el-table-column>
          <el-table-column key="5" prop="detail" label="企业详情">
          </el-table-column>
          <el-table-column key="6" prop="status" label="状态">
          </el-table-column>
        </template>
      </el-table>
    </div>

  </div>
</template>
<script>
export default {
  components: {},
  data() {
    return {
      tabIndex: 1,
      enterprisesTab: [
        {
          id: 1,
          name: "人工智能榜",
        },
        {
          id: 2,
          name: "企业百强榜",
        },
      ],
      tableList: [
        {
          id: 1,
          name: "测试",
          detail: "详情",
          status: "已完成",
        },
        {
          id: 1,
          name: "测试",
          detail: "详情",
          status: "已完成",
        },
        {
          id: 1,
          name: "测试",
          detail: "详情",
          status: "已完成",
        },
      ],
    };
  },
  mounted() {},
  methods: {
    changeIndex(id) {
      this.tabIndex = id;
    },
  },
};
</script>
<style lang="scss" scoped>
.table {
  padding: 30px;
  border: 1px solid #eee;
  margin: 100px auto;
  width: 800px;
}

.tab-item-main {
  margin-bottom: 20px;
  display: flex;
  flex-wrap: wrap;
  column-gap: 12px;
  row-gap: 4px;
  .tab-item {
    padding: 7px 15px;
    height: 33px;
    background: #f3f8ff;
    border-radius: 4px;
    transition: all 0.4s;
    cursor: pointer;
    color: #1d2745;
    .tab-item-text {
      width: fit-content;
      font-size: 14px;
      font-family: PingFang SC, PingFang SC-Medium;
      font-weight: 500;
    }
  }
  .tab-item-click {
    background: rgb(13, 147, 209);
    color: #ffffff;
  }
}
</style>

4、v-for之后 this.$refs变成数组

  • 普通的ref对象
    <div ref="one">第一个ref</div>
    <div ref="two">第二个ref</div>

console.log("$refs", this.$refs);

打印结果:

image.png

image.png

如果想获取ref对象的某个属性,语法为 this.$refs[ref对象名称].属性名

console.log("$refs", this.$refs['one'].innerHTML);  //第一个ref
  • v-for之后 refs对象
    <div class="ref-main">
      <div class="ref-item" :ref="`item${index}`"
        v-for="(item,index) in textArr" :key="index">
        {{ item}}</div>
    </div>
    
  data() {
    return {
      textArr: ["元素选择器", "class选择器", "id选择器", "通配符选择器"],
    };
  },
  
 console.log("$refs", this.$refs);

打印结果:

每一个ref对象都是一个数组

image.png

image.png

如果想获取ref对象的某个属性,语法为 this.$refs[ref对象名称][0].属性名

console.log("$refs", this.$refs['item0'][0].innerText);
  • 原因分析

假设你的 ref 不是动态的,而是静态的,ref="a",那么不管你执行多少次循环,最后 ref 只会有一个值,所以 vue 为了处理这种情况,会把 v-for 里 ref 转为数组形式

image.png

所以当我们使用 v-for 循环动态生成 ref 时,他也会生成一个数组

CSS

相邻兄弟选择器的妙用

场景描述

一列展示多个按钮,每个按钮之间间隔10px

image.png

实现方法

每个按钮设置 margin-left为10px,然后单独设置第一个按钮的margin-left为0px;

image.png

改良方法(相邻兄弟选择器)

只需设置一次 margin-left

image.png

  • 缺点:

如果按钮太多,需要换行展示的话,第二行开头的第一个按钮也会有 margin-left

image.png

  • 解决方法:

使用flex布局、gap属性

image.png

效果如下:

image.png

这个方法用起来十分方便,不过有个情况下是不能使用flex布局的

就是只展示一行按钮,按钮过多的话,就显示省略号

image.png

需要使用以下css属性,会和 display: flex 冲突

image.png

因此只能使用相邻兄弟选择器

image.png

案例完整代码(vue版本)

<template>
  <div class="contain">
    <div class="icon-main ellipsis_1">
      <div class="icon-item" v-for="(icon,index) in iconArr" :key="index"
        :title="icon">
        <div class="icon-item-text">{{ icon }}</div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  data() {
    return {
      iconArr: [
        "元素选择器",
        "class选择器",
        "id选择器",
        "通配符选择器",
        "通配符选择器",
        "通配符选择器",
        "通配符选择器",
      ],
    };
  },
  mounted() {},
  methods: {},
};
</script>
<style lang="scss" scoped>
.contain {
  padding: 30px;
  border: 1px solid #eee;
  margin: 100px auto;
  width: 800px;
  .icon-main {
    .icon-item {
      cursor: pointer;
      display: inline-block;
      padding: 0 20px;
      height: 40px;
      background: #09bef5;
      border-radius: 8px;
      .icon-item-text {
        height: 40px;
        line-height: 40px;
        text-align: center;
        font-size: 15px;
        font-family: PingFang SC, PingFang SC-Regular;
        color: #fff;
      }
    }
    .icon-item + .icon-item {
      margin-left: 10px;
    }
  }
  .ellipsis_1 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
    -webkit-line-clamp: 1;
  }
}
</style>