技术分享
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
    • h5项目问题总结
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)

刘誉

总有人要赢,为什么不能是我
首页
  • JavaScript

    • 构造函数和原型
    • Cookie和Session
    • Object.create(null)和{}
    • TypeScript配置
    • typescript入门到进阶
  • 框架

    • Vue-Router
    • React基础入门
  • 其它

    • Http协议
    • 跨域问题总结
  • 分析Promise实现
  • Axios源码分析
  • Webpack原理
  • vueRouter源码分析
  • Vue

    • Vite快速搭建Vue3+TypeScript项目
    • Cordova打包Vue项目的问题
    • Vue将汉字转为拼音,取出首字母
    • h5项目问题总结
  • JavaScript

    • new Function
  • 后端

    • Node.js中使用Crypto生成Token
    • Body-Parser处理多层对象的问题
  • 其它

    • 项目Demo汇总
    • Vuepress+Vercel搭建个人站点
    • 项目中能用到的
    • husky规范代码提交
  • Mongoose基础
  • Multer文件上传中间件的使用
  • JavaScript

    • 浅谈两数全等
    • JavaScript进制转换
    • 手写bind,apply,call和new
  • 算法

    • 数组去重和排序
    • 数组扁平化
    • 斐波那契数列
  • JavaScript 数据结构
  • 其它

    • webpack面试题
    • vite面试题
    • svg和canvas的优缺点
    • TypeScript面试题
    • Vue常见面试题
  • 计算机网络

    • 数据链路层
    • 网络层
  • Git的使用
  • Nginx的使用
  • CentOS7安装Nginx
  • 正则表达式
  • SEO搜索引擎优化
  • Serverless介绍
友链
GitHub (opens new window)
  • 项目 Demo 汇总
  • node中使用crypto生成token
  • new Function
  • body-parser处理多层对象的问题
  • Vite快速搭建Vue3+TypeScript项目
  • Cordova打包Vue项目的问题
  • Vue将汉字转为拼音,取出首字母
  • 项目中能用到的
  • Vuepress+Vercel搭建个人站点
  • husky规范代码提交
  • h5项目问题总结
  • vue动态换行,行末省略
    • css 单行省略无法实现原因
    • 实现方案一
    • 实现方案二
  • mocks项目复盘
  • 项目
coderly
2022-01-06

vue动态换行,行末省略

# vue 动态换行,行末省略

vue sfc 场景描述

  1. 一行可展示多个记录
  2. 单个记录超过一行,换行展示,文末省略
  3. 单个记录无法占满一行,可与多个无法占满一行的记录共一行
  4. 记录展示顺序按返回的数组内容一致,无需先根据内容长度排序

需求效果:

需求效果

# css 单行省略无法实现原因

我们一般在看到单行省略,脑中都会想到用 css

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
1
2
3

无法实现原因:

  1. 元素必须是 块状元素,首先便不满足一行多个记录的情况,直接排除

# 实现方案一

  1. 手动计算截取(需要优先知道一行最多能放几个字符)
  2. 针对非中文字符(预估以两个非中文字符占一个中文字符的宽度,不准)

html

<span class="tags" auId="au__tag">
  {{ formatName(item.value) }}
</span>
1
2
3

js

methods: {
    formatName(name) {
      if (!name) return ''
      // 特殊字符
      const _reg = /[0-9a-zA-Z,./\]{}()?|~`!@#$^&*<>+-=_ ]/g
      let validCount = 0
      let i = 0
      // 以一行最多占23个字符来算
      while (validCount < 23 && i < name.length) {
        if (_reg.test(name[i])) validCount += 0.5 // 如果是非中文字符,只占0.5个字符
        else validCount += 1
        i++
      }
      // 行末截断,省略
      return validCount >= 23 ? name.slice(0, i) + '...' : name
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

css

.tags {
  display: inline-block; /* 设置为行内块状元素 */
  margin: 24rpx 24rpx 0 0;
  font-size: 26rpx;
  line-height: 36rpx;
  padding: 10rpx 24rpx;
  background: #f8f8f8;
  border-radius: 27rpx;
  user-select: none;
}
1
2
3
4
5
6
7
8
9
10

缺点:

  1. 需要预先知道一行最多能占几个字符(最好实践是在用 rem 的移动端)
  2. 预估非中文字符占的宽度,不准确

缺点效果:
缺点效果

优点:

  1. 可以给当前元素添加额外的内容,比如:右上角的删除按钮(该元素没有添加 overflow: hidden)

优点效果:
优点效果

# 实现方案二

  1. 通过 vue 自定义指令实现 (opens new window)
  2. 在指令 inserted 钩子中计算当前 body 宽度,以及当前 记录 占的宽度
  3. 如果超出了 body 的宽度,就给当前元素添加 单行省略的代码

html

<span class="tags" auId="au__tag" v-ellipsis="60">
  <!-- 60: 是指当前内容占满一行时,加上60刚好是body的宽度,需要手动传入 -->
  {{ formatName(item.value) }}
</span>
1
2
3
4

js

export default {
  directives: {
    ellipsis: {
      inserted(el, binding, vnode) {
        let width = vnode.context.$root.domWidth; // 去缓存的 body 的宽度
        if (!width) {
          // 通过根组件缓存当前body宽度,不用多次计算
          vnode.context.$root.domWidth = width = document.body.clientWidth;
        }
        const textWidth = el.clientWidth; // 当前元素的宽度
        const W = binding.value || 0; // 针对添加了 padding的需要手动传入大小,
        if (width <= textWidth + W) {
          // 如果当前元素的宽度 + padding * 2  大于等于 body 的宽度
          // 说明当前元素已经超出一行了,此时添加单行省略
          el.style.display = "block";
          el.style.textOverflow = "ellipsis";
          el.style.overflow = "hidden";
        }
      },
      update(el, binding, vnode) {
        const width = vnode.context.$root.domWidth;
        if (!width) {
          // 如果 update 执行了,说明 inserted 已经执行过了,width会存在
          return;
        }
        const textWidth = el.clientWidth;
        const W = binding.value || 0;
        if (width <= textWidth + W) {
          el.style.display = "block";
          el.style.textOverflow = "ellipsis";
          el.style.overflow = "hidden";
          el.style.whiteSpace = "nowrap";
        }
      },
    },
  },
};
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

css

.tags {
  display: inline-block; /* 设置为行内块状元素 */
  margin: 24rpx 24rpx 0 0;
  font-size: 26rpx;
  line-height: 36rpx;
  padding: 10rpx 24rpx;
  background: #f8f8f8;
  border-radius: 27rpx;
  user-select: none;
  white-space: nowrap; /* 设置文本不换行 */
}
1
2
3
4
5
6
7
8
9
10
11

效果:
需求效果

缺点:

  1. 需要一个参照物,上面例子是以 body 为参照物,来计算一行的最大宽度
  2. 因为添加了 overflow: hidden,所以如果要给 当前元素添加 右上角的关闭按钮将无法实现

eg:
右上角的关闭按钮将无法实现

优点:

  1. 可以自定义参照物,比如当前元素的父节点。

自定义参照物

export default {
  directives: {
    ellipsis: {
      inserted(el, binding, vnode) {
        let width = vnode.context.$root.domWidth;
        if (!width) {
          vnode.context.$root.domWidth = width =
            vnode.context.$parent.$el.clientWidth; // 以当前元素的直接父级作为参照物,计算一行宽度
        }
        const textWidth = el.clientWidth;
        const W = binding.value || 0;
        if (width <= textWidth + W) {
          el.style.display = "block";
          el.style.textOverflow = "ellipsis";
          el.style.overflow = "hidden";
        }
      },
    },
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
上次更新: 2022/01/06, 19:59:43
h5项目问题总结
mocks项目复盘

← h5项目问题总结 mocks项目复盘→

最近更新
01
代码片段
04-22
02
koa全家桶
03-29
03
mocks项目复盘
03-29
更多文章>
Theme by Vdoing | Copyright © 2021-2022 coderly | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式