大屏开发的一次简单分享

258 阅读4分钟

日常开发的注意事项,针对大屏开发的遇到的常见问题做的一次简单分享……


针对大屏开发的遇到的常见问题做的一次简单培训,内容与演示效果在 realization 项目里的 demo 目录(暂不开源)。

一 销毁定时器

有创建定时器的行为,就该有销毁定时器的行为,setInterval 与 clearInterval 需要成对出现。否则组件销毁时定时器依然存在,继续运行着对应的方法,占用内存;而且当组件重建时,定时器再次激活,导致定时器内的行为重复发生。

示例代码:

setup() {
    const doSetInterval = () => {
      console.log(new Date())
    }
    let interval
    onMounted(() => {
      interval = setInterval(doSetInterval, 10000)
    })
    onUnmounted(() => {
      clearInterval(interval)
    })

    return {}
}

二 事件委托与销毁自定义事件

添加到页面上的事件处理程序越多,内存中的对象就越多,造成页面渲染和就绪时间延迟、事件不灵敏等性能问题。可以通过“事件委托”和适时移除事件的方式减少内存消耗,优化性能。

1 事件委托

利用事件冒泡的机制,指定一个事件处理程序来管理同一类型的所有事件,一般情况下就是把子元素的相同的事件都挂到父元素上,通过单个父元素代理多个子元素的事件。

示例代码:

<ul id="links">
    <li id="doSomething">doSomething</li>
    <li id="goSomewhere">goSomewhere</li>
    <li id="sayHi">say hi</li>
</ul>

var list = document.getElementById('links');
EventUtil.addHandler(list, 'click', function(e){
    e = EventUtil.getEvent(e);
    var target = EventUtil.getTarget(e);

    switch(target.id) {
        case 'doSomething':
            document.title = 'the document’s title was changed';
            break;
        case 'goSomewhere':
            location.href = 'http://www.baidu.com';
            break;
        case 'sayHi':
            alert('hi');
            break;
    }
})

2 销毁自定义事件

Vue 原生的事件会随着组件的卸载而自动销毁,但是通过 addEventListener 或类似方式自定义的事件并不会随着组件的卸载而销毁,需要手动销毁,否则事件会继续占用着内存。

示例代码:

setup() {
    const eventDom = ref(null)

    const handleClick = (e) => {
      e.target.style.color = 'red'
    }
    
    onMounted(() => {
      if(eventDom.value) eventDom.value.addEventListener('click', handleClick)
    })
    onUnmounted(() => {
      if(eventDom.value) eventDom.value.removeEventListener('click', handleClick)
    })

    return {}
}

三 z-index

z-index 不是越大越好,不要动不动就设置为 999999!z-index 是 兄弟之间的比较,如果父级容器的z-index 小,那设置再高也遮盖不住堂兄弟的节点,详细说明可以参考 层叠样式表。realization 项目中有简单的演示。

以前看过一篇 blog,说 z-index 取 -1、0、1 三个值就可以满足所有情况,当然我们对 dom 的设计可能比不过人家的设计,但我觉得取到 10 已经足够用了。

取值说明
auto盒子不会创建一个新的本地堆叠上下文。在当前堆叠上下文中生成的盒子的堆叠层级和父级盒子相同。
整型数字生成的盒子在当前堆叠上下文中的堆叠层级。此盒子也会创建一个堆叠层级为 0 的本地堆叠上下文。这意味着后代(元素)的 z-indexes 不与此元素的外部元素的 z-indexes 进行对比。

四 防抖与节流

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。这防止事件的高频触发,避免消耗大量又不必要的性能。

代码示例:


setup() {
    function debounce(fn,delay){
        let timer = null //借助闭包
        return function() {
            if(timer){
                clearTimeout(timer) 
            }
            timer = setTimeout(fn,delay) // 简化写法
        }
    }

    const consoleLog = () => {
      console.log(e.pageX)
    }
    
    onMounted(() => {
        window.addEventListener('keyup', debounce(consoleLog, 100))
    })

    onUnmounted(() => {
      window.removeEventListener('keyup', debounce(consoleLog, 100))
    })

    return {}
}

节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间
           return false 
       }
       // 工作时间
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}

五 滚动距离

开发大屏时,对于滚动元素,比如 parent.scrollLeft += 1, 每次滚动 1px ,但通常我们会缩小分辨率来开发,如果缩小为原分辨率的 50%,那么 parent.scrollLeft 自增的是 0.5,这种情况下浏览器对小于 1 的距离默认设为 0,所以实际是看不到滚动效果的,这时可以用 parent.scrollLeft += 2或更大的值来调试。

六 Eventloop

内容见js 事件循环(Event Loop)机制

七 销毁 echarts

有 echartsInstance(echarts 实例) 的地方,必有 echartsInstance.dispose()。否则来回切换组件实例会产生不必要的错误渲染。

let chart
onMounted(() => {
  chart = echarts.init(document.getElementById('id'))
})
onUnmounted(() => {
  chart.dispose()
})