小希

小希 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

小希 收藏了文章 · 4月6日

Vue 拖拽实现及问题备忘

以下备忘拖拽的简单实现和其中存在的问题,以此为基石可以扩展开发多种拖拽效果。

1. 拖拽样式

如下图,我们想实现的效果为:

当方块从上方灰块被拖拽到下方时,下方灰块中会出现该方块。

让我们先把以上页面效果实现:

<style scoped>
    .drag-field,
    .drop-field{
        height: 10rem;
        box-sizing: border-box;
        padding: 1rem;
        background-color: #eee;
        margin-top: 1rem;
        display: flex;
        justify-content: space-around;
        align-items: center;
    }

    .item{
        width: 30%;
        height: 3rem;
        text-align: center;
        line-height: 3rem;
        font-size: .9rem;
        background-color: royalblue;
        color: #eee;
    }
    .item:hover{
        cursor: pointer;
    }
</style>

<template>
    <div class="hello">
        <div class="drag-field">
            <div class="item"
                 v-for="(item, index) in items" :key="index"
            >
                {{ item.label }}
            </div>
        </div>
        <div class="drop-field">
            <div class="item" v-if="droppedItem !== ''">
                {{ droppedItem }}
            </div>
        </div>
    </div>
</template>

<script>
/* eslint-disable */
    export default {
        name: '',
        data () {
            return {
                droppedItem: '',
                items: [
                    {
                        id: 1,
                        label: '模块一'
                    },
                    {
                        id: 2,
                        label: '模块二'
                    },
                    {
                        id: 3,
                        label: '模块三'
                    }
                ]
            }
        }
    }
</script>

2. 拖拽相关事件

为了让 DOM 元素可以拖拽,我们需要为元素增加 draggable="true"

<div class="item"
     draggable="true"
     v-for="(item, index) in items" :key="index"
>
    {{ item.label }}
</div>

2.1 拖拽事件介绍

  • @dragstart:拖拽开始事件,可绑定于被拖拽元素上;
  • @dragend:拖拽结束事件,可绑定于被拖拽元素上;
  • @dragover:拖拽持续移动事件,建议绑定于可拖放区域(下方灰色块);
  • @dragenter:进入拖放区域,建议绑定于可拖放区域(下方灰色块),该事件仅在进入拖放区域时触发,在其内部移动时不触发,离开某一可拖放区域后再进入时会再次触发;

2.2 ondrop

拖放事件,绑定于可拖放区域上。

之所以把这个方法单独拎出来,是因为在使用该方法时存在一些注意事项。

当我们这样使用时:

<div class="drop-field"
     @drop="drop"
>
    ...
</div>


methods: {
    drop (event) {
        console.log('drop', event)
    }
}

发现当我们将可拖拽元素拖放至此时,并没有触发事件。

根据 MDN 的文档:

A listener for the dragenter and dragover events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling for these events is to not allow a drop.", hence the only way for the drop event to be fired is to first cancel the dragenter or dragover event.

我们必须阻止某一 DOM 元素对 dragover 的默认行为,才能使 drop 事件在其上正确执行:

<div class="drop-field"
     @drop="drop"
     @dragover="dragover"
>
    ...
</div>

methods: {
    drop (event) {
        console.log('drop', event)
    },
    dragover (event) {
        event.preventDefault()
    }
}

在 Vue 中,我们可以将组织默认行为的过程简写如下:

@dragover="dragover"

# 改为:

@dragover.prevent

2.3 DragEvent

注意,无论是 dragxxx 或 drop 事件,其传递的参数都是 DragEvent。

让我很费解的是,对于在拖放区绑定的 drop 事件而言,其 DragEvent 中竟然无法找到被拖拽元素。

这也就意味着,不借助额外变量,drop 事件是无法知道被拖放者是什么的。

但我们仍可以借助 DragEvent 中的 DataTransfer 来进行被拖放对象的消息传递。

流程如下:

2.3.1 在被拖拽对象的 dropstart 事件中传递消息

<div class="item"
     draggable="true"
     @dragstart="dragstart"
     v-for="(item, index) in items" :key="index"
>
    {{ item.label }}
</div>


dragstart (event) {
    console.log('dragstart', event)
    event.dataTransfer.setData('my-info', 'hello')
    event.dataTransfer.setData('my-extra-info', 'world')
}     

2.3.2 在拖放区的 drop 事件中获取消息

<div class="drop-field"
     @drop="drop"
     @dragover.prevent
>
    <div class="item"
         v-if="droppedItem !== ''">
        {{ droppedItem }}
    </div>
</div>

drop (event) {
    console.log('drop', event)
    console.log(event.dataTransfer.getData('my-info'))
    console.log(event.dataTransfer.getData('my-extra-info'))
}

2.3.3 在被拖拽对象的 dragend 事件中清除消息

<div class="item"
     draggable="true"
     @dragstart="dragstart"
     @dragend="dragend"
     v-for="(item, index) in items" :key="index"
>
    {{ item.label }}
</div>

dragend (event) {
    console.log('dragend', event);
    event.dataTransfer.clearData()
}

2.3.4 注意事项一:不能在被拖拽对象的 dragend 事件中传递消息

在整个拖拽过程中,事件的先后顺序为:

Step1: 拖拽对象的 dropstart;
Step2: 拖放区的 drop;
Step3:拖拽对象的 dropend;

因而,如果在 dragend 中传递消息,是不能被 drop 捕获的。

2.3.5 注意事项二:不能在被拖拽对象的 dragover 事件中传递消息

如果我们在被拖拽对象的 dragover 事件中传递消息,由于 dragover 事件的作用对象是「可拖放区」,即此时,该 dragover 中的 DragEvent 是以「可拖放区」身份施加的,故而不会传递到 drop 中。

2.3.6 注意事项三:消息只能是 String 类型

dataTransfer 中设置的消息( 即 setData 的第二个参数 )只能是字符串类型。如果想要传递对象,需要先进行序列化。

2.3.7 注意事项四:Vue 中事件参数

在上面的代码中,如果我们在 @dragstart 中想传递一些参数,如下:

@dragstart="dragstart(item)"

就会遇到一个问题:默认传递的 DragEvent 参数丢失了。

此时,我们需要使用 Vue 的特殊变量来实现事件参数的传递:

@dragstart="dragstart($event, item)"

3. 拖拽实现

结合以上内容,我们的实现思路如下:

代码如下:

<div class="item"
     draggable="true"
     @dragstart="dragstart($event, item)"
     @dragend="dragend"
     v-for="(item, index) in items" :key="index"
>
    {{ item.label }}
</div>

<div class="drop-field"
     @drop="drop"
     @dragover.prevent
>
    <div class="item"
         v-if="droppedItem !== ''">
        {{ droppedItem }}
    </div>
</div>


methods: {
    drop (event) {
        this.droppedItem = event.dataTransfer.getData('item')
    },
    dragstart (event, item) {
        event.dataTransfer.setData('item', item.label)
    },
    dragend (event) {
        event.dataTransfer.clearData()
    }
}

在 Vue 项目中,被拖拽对象和可拖放区域可能放在不同组件之中,此时,关键数据的传递最好借助 Vuex 等数据总线实现。让数据而非 DOM 流转是 Vue 项目的基本思路。

参考链接

  1. DataTransfer - Web API 接口 | MDN
  2. HTML5 drag & drop 拖拽与拖放简介 « 张鑫旭-鑫空间-鑫生活
  3. Vue.js里面点击事件传递了参数还能使用事件参数吗?如何使用? - radical的回答 - SegmentFault 思否
  4. DataTransfer.setData() - Web API 接口 | MDN
  5. HTML5 Drag and Drop events with Vue | Vue.js Discussion
  6. ondrop Event
查看原文

小希 收藏了文章 · 2020-11-24

Lottie-前端实现AE动效

项目背景

在海外项目中,为了优化用户体验加入了几处微交互动画,实现方式是设计输出合成的雪碧图,前端通过序列帧实现动画效果:
图片描述
序列帧:
图片描述
动画效果:
图片描述
序列帧:
图片描述
帧动画的缺点和局限性比较明显,合成的雪碧图文件大,且在不同屏幕分辨率下可能会失真。经调研发现,Lottie是个简单、高效且性能高的动画方案。


Lottie是可应用于Android, iOS, Web和Windows的库,通过Bodymovin解析AE动画,并导出可在移动端和web端渲染动画的json文件。换言之,设计师用AE把动画效果做出来,再用Bodymovin导出相应地json文件给到前端,前端使用Lottie库就可以实现动画效果。
图片描述

Bodymovin插件的安装与使用

  1. 关闭AE
  2. 下载并安装ZXP installer
    https://aescripts.com/learn/z...
  3. 下载最新版bodymovin插件
    https://github.com/airbnb/lot...
  4. 把下载好的bodymovin.zxp拖到ZXP installer
    图片描述
  5. 打开AE,在菜单首选项->常规中勾选☑️允许脚本写入文件和访问网络(否则输出JSON文件时会失败)
    图片描述
  6. 在AE中制作动画,打开菜单窗口->拓展->Bodymovin,勾选要输出的动画,并设置输出文件目录,点击render
    图片描述
    打开输出目录会看到生成的JSON文件,若动画里导入了外部图片,则会在images中存放JSON中引用的图片

前端使用lottie

静态URL
https://cdnjs.com/libraries/l...

NPM

npm install lottie-web

调用loadAnimation

lottie.loadAnimation({
  container: element, // 容器节点
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'data.json' // JSON文件路径
});

vue-lottie

也可以在vue中使用lottie

    import lottie from '../lib/lottie';
    import * as favAnmData from '../../raw/fav.json';

    export default {
        props: {
            options: {
                type: Object,
                required: true
            },
            height: Number,
            width: Number,
        },

        data () {
            return {
                style: {
                    width: this.width ? `${this.width}px` : '100%',
                    height: this.height ? `${this.height}px` : '100%',
                    overflow: 'hidden',
                    margin: '0 auto'
                }
            }
        },

        mounted () {
            this.anim = lottie.loadAnimation({
                    container: this.$refs.lavContainer,
                    renderer: 'svg',
                    loop: this.options.loop !== false,
                    autoplay: this.options.autoplay !== false,
                    animationData: favAnmData,
                    assetsPath: this.options.assetsPath,
                    rendererSettings: this.options.rendererSettings
                }
            );
            this.$emit('animCreated', this.anim)
        }
    }

loadAnimation参数

container用于渲染动画的HTML元素,需确保在调用loadAnimation时该元素已存在
renderer渲染器,可选值为'svg'(默认值)/'canvas'/'html'。svg支持的功能最多,但html的性能更好且支持3d图层。各选项值支持的功能列表在此
loop默认值为true。可传递需要循环的特定次数
autoplay自动播放
pathJSON文件路径
animationDataJSON数据,与path互斥
name传递该参数后,可在之后通过lottie命令引用该动画实例
rendererSettings可传递给renderer实例的特定设置,具体可看

Lottie动画监听

Lottie提供了用于监听动画执行情况的事件:

  • complete
  • loopComplete
  • enterFrame
  • segmentStart
  • config_ready(初始配置完成)
  • data_ready(所有动画数据加载完成)
  • DOMLoaded(元素已添加到DOM节点)
  • destroy

可使用addEventListener监听事件

// 动画播放完成触发
anm.addEventListener('complete', anmLoaded);

// 当前循环播放完成触发 
anm.addEventListener('loopComplete', anmComplete);

// 播放一帧动画的时候触发 
anm.addEventListener('enterFrame', enterFrame);

控制动画播放速度和进度

可使用anm.pause和anm.play暂停和播放动画,调用anm.stop则会停止动画播放并回到动画第一帧的画面。
使用anm.setSpeed(speed)可调节动画速度,而anm.goToAndStop(value, isFrame)和anm.goToAndPlay可控制播放特定帧数,也可结合anm.totalFrames控制进度百分比,比如可传anm.totalFrames - 1跳到最后一帧。

anm.goToAndStop(anm.totalFrames - 1, 1);

这样的好处是可以把相关联的JSON文件合并,通过anm.goToAndPlay控制动画状态的切换,如下图例中一个JSON文件包含了2个动画状态的数据:
图片描述

图片资源

JSON文件里assets设置了对图片的引用:
图片描述
若想统一修改静态资源路径或者设置成绝对路径,可在调用loadAnimation时传入assetsPath参数:

lottie.loadAnimation({
  container: element,
  renderer: 'svg',
  path: 'data.json',
  assetsPath: 'URL'  // 静态资源绝对路径
});

功能支持列表

即使用bodymovin成功输出了JSON文件(没有报错),也会出现动效不如预期的情况,比如这是在AE中构建的形象图:
图片描述
但在页面中渲染效果是这样的:
图片描述
这是因为使用了不支持的Merge Paths功能
图片描述
因此对设计师而言,创建Lottie动画和往常制作AE动画有所不同,此文档记录了Bodymovin支持输出的AE功能列表,动画制作前需跟设计师沟通好,根据动画加载平台来确认可使用的AE功能。

除此之外,尽量遵循官方文档里对设计过程的指导和建议

  • 动画简单化。创建动画时需时刻记着保持JSON文件的精简,比如尽可能地绑定父子关系,在相似的图层上复制相同的关键帧会增加额外的代码,尽量不使用占用空间最多的路径关键帧动画。诸如自动跟踪描绘、颤动之类的技术会使得JSON文件变得非常大且耗性能。
  • 建立形状图层。将AI、EPS、SVG和PDF等资源转换成形状图层否则无法在Lottie中正常使用,转换好后注意删除该资源以防被导出到JSON文件。
  • 设置尺寸。在AE中可设置合成尺寸为任意大小,但需确保导出时合成尺寸和资源尺寸大小保持一致。
  • 不使用表达式和特效。Lottie暂不支持。
  • 注意遮罩尺寸。若使用alpha遮罩,遮照的大小会对性能产生很大的影响。尽可能地把遮罩尺寸维持到最小。
  • 动画调试。若输出动画破损,通过每次导出特定图层来调试出哪些图层出了问题。然后在github中附上该图层文件提交问题,选择用其他方式重构该图层。
  • 不使用混合模式和亮度蒙版
  • 不添加图层样式
  • 全屏动画。设置比想要支持的最宽屏幕更宽的导出尺寸。
  • 设置空白对象。若使用空白对象,需确保勾选可见并设置透明度为0%否则不会被导出到JSON文件。

预览效果

由于以上所说的功能支持问题会导致输出动画效果不确定性,设计师和前端之间有个动画效果联调的过程,为了提高联调效率,设计师可先进行初步的效果预览,再把文件交付给前端。

方法1:输出预览HTML文件

渲染前设置所要渲染的文件
图片描述
勾选☑️Demo选项
图片描述
在输出的文件目录中就可找到可预览的demo.html文件

方法2:LottieFiles分享平台

把生成的JSON文件传到LottieFiles平台,可播放、暂停生成文件的动画效果,可设置图层颜色、动画速度,也可以下载lottie preview客户端在iOS或Android机子上预览。
图片描述
LottieFiles平台还提供了很多线上公开的Lottie动画效果,可直接下载JSON文件使用
图片描述

交互hack

Lottie的不足之处是没有对应的API操纵动画层,若想做更细化的动画处理,只能直接操作节点来实现。比如当播放完左图动画进入惊讶状态后,若想实现右图随鼠标移动而控制动画层的简单效果:
图片描述图片描述
开启调试面板可以看到,lottie-web通过使用<g>标签的transform属性来控制动画:
图片描述

当元素已添加到DOM节点,找到想要控制的<g>标签,提取其transform属性的矩阵值,并使用rematrix解析矩阵值。

onIntroDone() {
    const Gs = this.refs.svg.querySelectorAll('svg > g > g > g');
    Gs.forEach((node, i) => {
        // 过滤需要修改的节点
        ...

        // 获取transform属性值
        const styleArr = node.getAttribute('transform').split(',');
        styleArr[0] = styleArr[0].replace('matrix(', '');
        styleArr[5] = styleArr[5].replace(')', '');
        const style = `matrix(${styleArr[0]}, ${styleArr[1]}, ${styleArr[2]}, ${styleArr[3]}, ${styleArr[4]},                     ${styleArr[5]})`;

        // 使用Rematrix解析
        const transform = Rematrix.parse(style);
        this.matrices.push({
            node,
            transform,
            prevTransform: transform
      });
    }
}

监听鼠标移动,设置新的transform属性值。

onMouseMove = (e) => {
    this.mouseCoords.x = e.clientX || e.pageX;
    this.mouseCoords.y = e.clientY || e.pageY;
      
    let x =  this.mouseCoords.x - (this.props.browser.width / 2);
    let y =  this.mouseCoords.y - (this.props.browser.height / 2);

    const diffX = (this.mouseCoords.prevX - x);
    const diffY = (this.mouseCoords.prevY - y);

    this.mouseCoords.prevX = x;
    this.mouseCoords.prevY = y;

    this.matrices.forEach((matrix, i) => {
        let translate = Rematrix.translate(diffX, diffY);
        const product = [matrix.prevTransform, translate].reduce(Rematrix.multiply);
        const css = `matrix(${product[0]}, ${product[1]}, ${product[4]}, ${product[5]}, ${product[12]}, ${product[13]})`;

        matrix.prevTransform = product;
        matrix.node.setAttribute('transform', css);
     })
  }

进一步优化

看到一个方法,在AE中将图层命名为#id格式,生成的SVG相应的图层id会被设置为id,命名为.class格式,相应的图层class会被设置为class
图片描述
试了下的确可以,如下图,因此可通过这个方法快速找到需要操作的动画层,进一步简化代码:
图片描述

小结

  1. Lottie的缺点在于若在AE动画制作的过程不注意规范,会导致数据文件大、耗内存和性能的问题;Lottie-web的官方文档不够详尽,例如assetsPath参数是在看源码的时候发现的;开放的API不够齐全,无法很灵活地控制动画层。
  2. 优点也很明显,Lottie能帮助提高开发效率,精简代码,易于调试和维护;资源文件小,输出动画效果保真;跨平台——Android, iOS, Web和Windows通用。
  3. 总的来说,Lottie的引用可以替代传统的GIF和帧动画,灵活利用好提供的属性和方法可以控制动画的播放,但需注意规范设计和开发的流程,才可以更高效地完成动画的制作与调试。
查看原文

小希 赞了文章 · 2020-11-13

ES6-ES10知识整合合集

目录

  • ECMAScript
  • ES2015
  • 新特性的分类
  • ES6-ES10学习版图
  • 基本语法链接整合

历经两个月,终于把所有的ES6-ES10的知识点都发布完成了,这里进行一个小的整合,以后方便查阅资料用。
这些东西打印出来A4纸也有120多页,一本小书的样子( ̄▽ ̄)/

有些东西遇到了网上查和自己整理一遍感觉还是不一样的,也希望自己可以慢慢有一种写作整理的习惯。语法是基础,还是要整体过一遍的,遇到了之后再查,心里没数都不知道从哪里查起。所以将每个部分做了个分类展示,这样查起来也好查✧(^_-✿

还是要对ECMAScript进行一下知识整理的

ECMAScript

ECMAScript通常看做JavaScript的标准化规范,实际上JavaScriptECMAScript的扩展语言,ECMAScript只是提供了最基本的语法。

每个前端人烂熟于心的公式:

JavaScript = ECMAScript + BOM + DOM

ES2015

  • 2015年开始保持每年一个版本的迭代,并且开始按照年份命名。
  • 相比于ES5.1的变化比较大
  • 自此,标准命名规则发生变化
  • ES6泛指是2015年之后的所有新标准,特指2015年的ES版本,以后要看清楚是特指还是泛指

新特性的分类

  • 解决原有语法上的一些问题或者不足
  • 对原有语法进行增强
  • 全新的对象、全新的方法、全新的功能
  • 全新的数据类型和数据结构

ES6-ES10学习版图

ES6-ES10学习版图

基本语法链接整合

ES6

ES7

ES8

ES9

ES10

查看原文

赞 74 收藏 64 评论 2

小希 赞了文章 · 2020-11-04

黑科技:CSS定制多行省略

转载请注明出处:http://hai.li/2017/03/08/css-...

什么是多行省略?

什么是多行省略

当字数多到一定程度就显示省略号点点点。最初只是简单的点点点,之后花样越来越多,点点点加下箭头,点点点加更多,点点点加更多加箭头...。多行省略就是大段文字后面的花式点点点。


同行这么做:

同行这么做

  1. Google Plus用透明到白色的渐变遮罩,渐变遮罩在文字超出的时候才显示,但无法挤出文字,且背景只能纯色,不理想。

  2. 豌豆荚则更简单粗暴换行显示,换行显示则文字未超出时依然显示 ...xxx,更不理想!

我这样做:

我这样做

在QQ浏览器的页面用了一个原创的mod-more UI组件,实现了定制的多行省略,还是纯CSS的,领先同行一大截,赞!赞!赞!只可惜,mod-more组件的高度是固定的。对mod-more进一步进化,完美自适应高度,而且代码简化易用。


怎么做到的?

怎么做到的


原理详解!

按需显示...更多

按需显示...更多

<!doctype html><html><body>
<style>@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}/*测试*/</style>
<div style="font-size:12px;line-height: 18px;-webkit-animation: width-change 8s ease infinite;background: rgb(230, 230, 230);">
    <div style="float:right;margin-left: -50px;width:100%;position:relative;background: hsla(229, 100%, 75%, 0.5);">腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。</div>
    <div style="float:right;position:relative;width:50px;height: 108px;color:transparent;background: hsla(334, 100%, 75%, 0.5);">placeholder</div>
    <div style="float:right;width:50px;height:18px;position: relative;background: hsla(27, 100%, 75%, 0.5);">...更多</div>
</div>
</body></html>

利用右浮动原理——右浮动元素从右到左依次排列,不够空间则换行。蓝色块、粉色块、橙色块依次右浮动,蓝色块高度小于6行文字时,橙色块在右边,蓝色块高度大于6行文字时,左下角刚好够橙色块排列的空间,于是橙色块就到左边了

按需显示...更多2

<!doctype html><html><body>
<style>@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}/*测试*/</style>
<div style="font-size:12px;line-height: 18px;-webkit-animation: width-change 8s ease infinite;background: rgb(230, 230, 230);">
    <div style="float:right;margin-left: -50px;width:100%;position:relative;background: hsla(229, 100%, 75%, 0.5);">腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。</div>
    <div style="float:right;position:relative;width:50px;height: 108px;color:transparent;background: hsla(334, 100%, 75%, 0.5);">placeholder</div>
    <div style="float:right;width:50px;height:18px;position: relative;background: hsla(27, 100%, 75%, 0.5);left: 100%;-webkit-transform: translate(-100%,-100%);">...更多</div>
</div>
</body></html>

进一步将橙色块偏移到正确位置就大功告成了!细心的同学会发现,将橙色块加上渐变底就是Google Plus在用的方案。

文字溢出截断

文字溢出截断

<!DOCTYPE html><html><body>
<style>@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}/*测试*/</style>
<div style="font-size: 12px;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 6;color: red;line-height: 18px;position: relative;-webkit-animation: width-change 8s ease infinite;background: rgb(230, 230, 230);">
    <div style="color:#000;display: inline;vertical-align: top;background: rgb(204, 204, 204);">腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。</div>
</div>
</body></html>

-webkit-line-clamp是webkit内核的私有css属性,用于进行多行省略,在安卓和ios上全支持。但它固定使用省略号,无法直接扩展。而且自带了溢出截断逻辑,作用于容器高度。仔细考察可发现它使用的省略号是单字符,可以用文字css属性如font-size,letter-spacing,color等控制。

文字溢出截断2

<!DOCTYPE html><html><body>
<style>@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}/*测试*/</style>
<div style="font-size: 36px;letter-spacing: 28px;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 6;color: red;line-height: 18px;position: relative;-webkit-animation: width-change 8s ease infinite;background: rgb(230, 230, 230);">
    <div style="color:#000;display: inline;font-size: 12px;vertical-align: top;letter-spacing: 0;background: rgb(204, 204, 204);">腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。</div>
</div>
</body></html>

设置外容器的font-sizeletter-spacingcolor,并在子容器里恢复就可以单独设置省略号。这里外容器设置font-size的值等于2倍行高(余下要撑开的宽度可用letter-spacing补足,也可仅用font-size撑开全部的宽度),color:transparent可以让line-clamp既挤出文字又不截断容器高度,外容器高度达到7行而不是默认表现的6行,从而达到需要的溢出截断效果

clipboard.png

合体!定制多行省略

合体!定制多行省略

<!DOCTYPE html><html><body>
<style>@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}/*测试*/</style>
<div style="position: relative;line-height:18px;-webkit-animation: width-change 8s ease infinite;max-height: 108px;">
    <div style="font-size: 36px;letter-spacing: 28px;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 6;color: transparent;line-height: 18px;position: relative;">
        <div style="font-size:12px;color: #000;display: inline;vertical-align: top;letter-spacing: 0;">
        腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。
        </div>
        <div style="position:absolute;top: 0;left: 50%;width: 100%;height: 100%;letter-spacing: 0;color: #000;font-size: 12px;background: rgba(173, 216, 230, 0.5);">
            <div style="float: right;width: 50%;height: 100%;background: rgba(255, 192, 203, 0.5);"></div>
            <div style="float: right;width: 50%;height: 108px;background: hsla(223, 100%, 50%, 0.19);"></div>
            <div style="float: right;width: 50px;height: 18px;position: relative;background: rgba(255, 165, 0, 0.5);" class="">... 更多</div>
        </div>
    </div>
</div>   
</body></html>

-webkit-line-clamp实现的文字溢出截断代码为主体,叠加绝对定位同步的按需显示...更多结构。因为绝对定位,这里使用百分比简化代码。最外包一层结构限制最大高度。

clipboard.png

<!DOCTYPE html><html><body>
<style>
/*
 * 行高 h
 * 最大行数 n
 * ...更多容器的宽 w
 * 字号 f
 */

@-webkit-keyframes width-change {0%,100%{width: 320px} 50%{width:260px}}
.ellipsis {
    position: relative;
    background: rgb(230, 230, 230);
    width: 260px;
    max-height: 108px; /* h*n */
    line-height: 18px; /* h */
    overflow: hidden;
    -webkit-animation: width-change 8s ease infinite;
}
.ellipsis-container {
    position: relative;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 6; /* n */
    font-size: 50px; /* w */
    color: transparent;
}
.ellipsis-content {
    color: #000;
    display: inline;
    vertical-align: top;
    font-size: 12px; /* f */
}
.ellipsis-ghost {
    position:absolute;
    z-index: 1;
    top: 0;
    left: 50%;
    width: 100%;
    height: 100%;
    color: #000;
}
.ellipsis-ghost:before {
    content: "";
    display: block;
    float: right;
    width: 50%;
    height: 100%;
}
.ellipsis-placeholder {
    content: "";
    display: block;
    float: right;
    width: 50%;
    height: 108px; /* h*n */
}
.ellipsis-more {
    float: right;
    font-size: 12px; /* f */
    width: 50px; /* w */
    height: 18px; /* h */
    margin-top: -18px; /* -h */
}
</style>
<div class="ellipsis">
    <div class="ellipsis-container">
        <div class="ellipsis-content">腾讯成立于1998年11月,是目前中国领先的互联网增值服务提供商之一。成立10多年来,腾讯一直秉承“一切以用户价值为依归”的经营理念,为亿级海量用户提供稳定优质的各类服务,始终处于稳健发展状态。2004年6月16日,腾讯控股有限公司在香港联交所主板公开上市(股票代号700)。</div>
        <div class="ellipsis-ghost">
            <div class="ellipsis-placeholder"></div>
            <div class="ellipsis-more">...更多</div>
        </div>
    </div>
</div>   
</body></html>

为什么这么做?

line-clamp有3宗罪

text-align:justify一起用会使省略号和文字相叠

text-align:justify一起用会使省略号和文字相叠

超出截断后会截掉部分行高

超出截断后会截掉部分行高

省略号出现在单词中间

省略号出现在单词中间

定制省略当然某问题啦

text-align:justify时如期所示,没问题!

text-align:justify时如期所示,没问题!

截断时如期所示,也没问题!

截断时如期所示,也没问题!

省略号在有单词时如期显示,依然没问题!

省略号在有单词时如期显示,依然没问题!

更别说点点点花样增改

后退,我要开始装逼了

简单增改文字加链接只是小case

简单增改文字加链接只是小case

用折角还是其他图片表示文本溢出可以增添趣味

用折角还是其他图片表示文本溢出可以增添趣味

溢出时显示溢出字数增加了实用用途

溢出时显示溢出字数增加了实用用途

这B装的beautiful

查看原文

赞 97 收藏 173 评论 23

小希 赞了回答 · 2020-07-08

解决el-form-item 包含多个input 怎么验证?

同样遇到这个问题,一个 el-form-item 里有两个input,主要是因为两个input是同一类,比如值的范围。
image.png

解决方法:
使用两个 el-form-item 嵌套。如下处理

<el-form ref="editForm" :model="editForm" :rules="FormRules" label-width="80px">
  <el-form-item label="餐后血糖" prop="pbg_min">
    <el-col :span="5">
      <el-form-item prop="pbg_min">
        <el-input-number size="mini" class="numberInput" :controls="false" v-model="editForm.pbg_min"></el-input-number> -
      </el-form-item>
    </el-col>
    <el-col :span="10">
      <el-form-item prop="pbg_max">
        <el-input-number size="mini" class="numberInput" :controls="false" v-model="editForm.pbg_max"></el-input-number> mmol/l
      </el-form-item>
    </el-col>
  </el-form-item>
  <el-form-item label="BMI" prop="bmi_min">
    <el-col :span="5">
      <el-form-item prop="bmi_min">
        <el-input-number size="mini" class="numberInput" :controls="false" v-model="editForm.bmi_min"></el-input-number> -
      </el-form-item>
    </el-col>
    <el-col :span="10">
      <el-form-item prop="bmi_max">
        <el-input-number size="mini" class="numberInput" :controls="false" v-model="editForm.bmi_max"></el-input-number>
        kg/m^2
      </el-form-item>
    </el-col>
  </el-form-item>
</el-form>

FormRules 里正常写字段校验规则即可。

关注 6 回答 4

小希 提出了问题 · 2019-11-13

el-collapse折叠面板组件中的其中一个面板内容是el-table,展开的时候高度异常

el-collapse-item 中放一个 el-table, 展开的时候高度先是比表格内容高,然后闪一下突然回到正常的高度, 请问有人遇到过这样的问题么,该如何解决?
如果el-collapse-item中放的是普通的文本或者 就不会出现这个问题

关注 4 回答 1

小希 提出了问题 · 2019-11-13

el-collapse折叠面板组件中的其中一个面板内容是el-table,展开的时候高度异常

el-collapse-item 中放一个 el-table, 展开的时候高度先是比表格内容高,然后闪一下突然回到正常的高度, 请问有人遇到过这样的问题么,该如何解决?
如果el-collapse-item中放的是普通的文本或者 就不会出现这个问题

关注 4 回答 1

小希 关注了用户 · 2019-11-13

shuangyueliao @shuangyueliao

关注 2976

小希 关注了用户 · 2019-11-13

政采云前端团队 @zhengcaiyunqianduantuandui

Z 是政采云拼音首字母,oo 是无穷的符号,结合 Zoo 有生物圈的含义。寄望我们的前端 ZooTeam 团队,不论是人才梯队,还是技术体系,都能各面兼备,成长为一个生态,卓越且持续卓越。

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

关注 2632

认证与成就

  • 获得 0 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-11-10
个人主页被 294 人浏览