zoukankan      html  css  js  c++  java
  • 我的2018前端踩坑记

    某著名小白说过 :世上本来到处都是坑,只要走的人多了,也就把坑都给埋了。该小白还说过:坑本身并不可怕,可怕的是踩了一次之后,还第二、第三次踩到了相同的坑。

    所谓"坑",主要是由于我们对某些知识点理解不够透彻,导致在应用的时出现了一些奇怪的问题。因为我们每个人,对于某个知识点的理解程度不一样,所以,有些坑我觉得真的很坑,但是你可能觉得一点都不坑,因为你早就对它了如指掌了。

    这里列举的一些坑,都是我过去一年在项目中所遇到过的,并当时在笔记中记录下来的,现在稍加整理就形成了这篇博客,以供日后查阅。

    不知不觉,开头又bb了这么多,还是赶紧进入正题哈。

    1. 设置透明度(opacity)引起的惨案

    之前做炉石盒子的天梯环境页面,地址是 炉石天梯环境 ,就在项目做得差不多的时候,准备上线了, QA 突然发现了如下的一个 bug:

    有一个选择排序方式的下拉菜单,它的定位是 position: absolute,正常来说,它应该会覆盖在其他元素之上的,可是为什么 0.14% 反而会覆盖在它上面呢? 在代码中找了好久,那个 0.14% 并没有设置 z-index属性,也没有 position: absolute 这样的东西,真是好郁闷哦。后来到 mdn 查文档才发现,原来是 opacity属性引起 的: opacity 属性值小于 1 的元素会创建新的层叠上下文 。因为当时我有个偷懒的做法,字体继承的颜色是 #666, 我想让 0.14% (天梯比率)颜色变浅一些,直接加了个 opacity: 0.6 ,导致了创建了新的层叠上下文,层级比下拉菜单高了,所以就覆盖在了上面。具体什么是层叠上下文,以及哪些属性会创建新的层叠上下文,这里也不介绍了有需要的可以参考一下 层叠上下文

    虽然上面描述得已经很详细了,但是可能由于我的表达能力不太好,有些朋友还不是很明白我的意思,可以看一下这里的 demo 代码:

    <div class="menu">
      <div class="title">下拉菜单</div>
      <div class="menu-list">
        <div class="item">菜单1</div>
        <div class="item">菜单2</div>
        <div class="item">菜单3</div>
      </div>
    </div>
    <div class="content">
      我是半透明的文字,可以覆盖在下拉菜单之上哦~
    </div>
    <style>
      .menu {
        position: relative;
      }
      .menu-list {
        display: none;
        position: absolute;
        background: #ccc;
      }
      .menu:hover .menu-list {
        display: block;
      }
      .content {
        opacity: 0.6;
      }
    </style>
    

    将鼠标移动到下拉菜单上,就会发现文字会发生重叠了:

    那这个坑有什么解决办法呢?最简单的就是下拉菜单添加个属性 z-index: 1 。另外,这里再啰嗦一下,就是z-index的值不要乱设置。以前刚刚接触前端时,会经常看一些视频教程,看到里面讲师动不动就设置个 z-index: 999 之类的特别大的数值。这是一个不好的习惯。张鑫旭老师在《CSS世界》一书中,提到了 不三原则 ,就是说一般情况下,z-index的值不要超过3,基本能满足大多数的需求了。

    2. flex布局:子项溢出后无法查看全部内容

    之前做漫画阅读器,因为漫画可能有长图片,也可能有短图片。长图片可以滚动查看,短图片就居中显示。所以,很自然会想到用 flex 布局来实现。简单的代码如下:

    <div class="app">
      <img src="https://m.tuniucdn.com/fb2/t1/G1/M00/F1/51/Cii9EFkAaZ-IRgGNAATB18ldk0UAAJzuQN-p1cABMHv15.jpeg" alt="">
    </div>
    <style>
    
      html,
      body {
        height: 100%;
      }
    
      .app {
        display: flex;
        height: 100%;
        justify-content: center;
        align-items: center;
      }
    
      img {
         100%;
      }
    </style>
    

    这里,我们的 .app 容器里面这里有一张很长的图片。当我们运行上面的代码,如果你仔细观察原图和页面显示的图片,就会发现图片的顶部和底部的一些内容看不到了,滚动条到了一定位置就无法滚动了。正常来说,我们应该可以通过滚动条的上下滑动看到图片的全部内容才对的。当时我想了很久也没有想出来原因,最后到 stackoverflow 找到了答案 Can't scroll to top of flex item that is overflowing container

    答案中有提到,可以设置子项的 margin: auto 来实现内容溢出时也自动居中(包括水平和垂直的):

    修改后的 CSS 代码如下:

      .app {
        display: flex;
        height: 100%;
      }
    
      img {
         100%;
        margin: auto;
      }
    

    所以,以后如果在使用 flex 布局实现居中,如果子项的内容会溢出 flex 容器 ,可以将子项设置为 margin: auto 试试。

    3. transfrom 和 fixed 不能在一起!

    CSS3 的 transform 属性也算是比较常用的,特别是做一些动画效果的时候,用它来移动元素的位置,性能会比设置 top 或 left 要高一些。但是,如果一个元素设置了 transform 属性,而它的子元素又设置 fixed 定位,那么这个 fixed 定位的子元素表现会有些奇怪,如下代码:

    <div class="app">
      <button onclick="layer.style.display='block'">弹出蒙层</button>
      <div class="layer" id="layer"></div>
    </div>
    
    <style>
      .app {
        position: relative;
         100px;
        height: 100px;
        background: #ccc;
        /* 使用transform让元素向下偏移20px */
        transform: translate(0, 20px);
      }
    
      .layer {
        display: none;
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background: rgba(0, 0, 0, 0.7);
      }
    </style>
    

    打开页面,效果是这样的:

    我们希望点击“弹出蒙层”按钮后,就显示个覆盖整个窗口的蒙层。但是结果却出乎意料。如下:

    蒙层只是遮住了小正方形,这不是我们想要的结果,因为我们知道,fixed 定位是相对于屏幕视口(viewport)定位的, 但是,本例却相对于它的父亲元素。这是为什么呢?如果认真查阅 mdn文档 ,就会找到答案:

    可见,问题的原因在于,我们只是记住了fixed是相对于 viewport 定位,但是也有特殊情况: 当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先 。所以,这并不是bug,是因为我基础不扎实导致的。事实上, 除了 transform 会改变 fixed 的定位元素之外,还有其他属性也会改变,ChokCoco大佬有一篇文章做了详细的讲解,想要了解更多的请点击 不受控制的 position:fixed

    那遇到这种情况怎么办呢?比较好的办法就是把 fixed 元素移到外面去,不要放到有 transform 属性的元素里面。但是,有时候我们没有办法移到外面怎么办呢?比如,这是它是一个子组件,它的某个父亲组件就是用了 transform,那怎么办呢?我也不知道怎么办,欢迎大家探讨一下哈哈哈~

    fixed 定位还具有其他的坑,这里也不展开了,有兴趣的可看 看github 上有大佬整理好的这篇文章 移动端web页面使用position:fixed问题总结

    4. 安卓微信视频播放器的层级问题

    我们都知道, video 标签设置了 playsinline 就可以内联播放视频,而不是全屏播放。(注意:前提是客户端的 Webview 配置了允许内联播放,所以有时候虽然设置了 playsinline,但在某些 app 里面打开依然是全屏播放,这不是前端的锅哦)。最近有一个需求,类似下面这样的:

    页面上有一个视频,视频播下面有一个按钮,点击按钮就弹出一个图片,该图片要覆盖整个屏幕,比如是这样的:

    示例代码如下:

    <video id="video" controls="" playsinline="" src="https://vod.cc.163.com/file/5bcbe1ae9efdc0608bb6d06b.mp4"></video>
    <img id="image" src="https://ds.163.com/2018/mrzh/appointment/static/img/bg-body.cdef1ec.jpg" alt="">
    <button id="button">弹出图片</button>
    <style>
      video,
      img {
         100%;
      }
    
      img {
        display: none;
        position: absolute;
        top: 0;
      }
    </style>
    
    <script>
      var video = document.getElementById('video');
      var image = document.getElementById('image');
      var button = document.getElementById('button');
      button.onclick = function() {
        image.style.display='block';
      }
      image.onclick = function() {
        this.style.display='none';
      }
    </script>
    

    但是,在安卓上却发现一个问题,开始播放视频后(注意,只有播放视频后才可以复现),点击“弹出图片”按钮,显示如下所示:

    图片无法覆盖在视频播放器上面。然后,我设置了 z-index 或者 transform ,都没有任何效果。最后, 剩下的可能原因就是: 安卓微信视频播放器实际上用的是原生组件。为了验证这一猜想,我们可以启用开发者选项的绘图模式 (开发者选项 --> 绘图 --> 显示布局边界,不同机型不一样,找不到的请百度找一下哈),结果如下:


    看到没有,视频是一个完整的有边框的东西,证明他是一个独立于 Webview 的原生组件。

    那怎么办呢?只能上网找答案呀!我们都知道,微信 webview 使用的是 X5 内核,所以我也希望能从它的开发者文档上找到一些有用的信息,好不容易找到了一篇叫做 H5同层播放器接入规范 。它说可以可以在 video 标签添加一个属性 x5-video-player-type ,并且给出的例子是这样的:

    <video src="http://xxx.mp4" x5-video-player-type="h5"/>
    

    我当时很高兴,以为问题就这样解决了,然并卵,添加了 x5-video-layer-type 属性之后,playsinlie 属性就失效了,无法内联播放了,只能全屏播放,所以,不能添加这个属性。

    然后我就想,既然无法覆盖这个视频,那在弹出图片的时候能不能把视频给隐藏掉?然后关闭图片的时候再把视频显示回来呢?于是就把 JS 代码改成下面这样:

      button.onclick = function() {
        image.style.display='block';
        video.style.display = 'none';
      }
      image.onclick = function() {
        this.style.display='none';
        video.style.display = 'block';
      }
    

    然后,这样就可以了。因为我在网上找不到更好的办法,如果大家遇到这个问题可以参考这种做法。当然,如果你们找到了有更好的办法,欢迎评论分享出来哈~

    关于安卓微信视频播放器的坑就先讲到这里啦。

    等等,一讲到原生组件,这里还得再补充一下微信小程序相关的东西,当然,我自己还没有过小程序的开发的经验, 这是之前的一次内部交流会,一位同事的分享:小程序在渲染的时候,大多数组件都是渲染成 HTML 组件,但是有少部分比如 canvas、 video、 input、 map 等会渲染成原生组件的。所以,如果你在写小程序时,想用一段文字覆盖在一个 canvas 上,发现怎么设置都无法实现,那是因为 canvas 渲染后是原生组件,而文字是 html 组件,所以无法覆盖上去的 。那有什么办法呢?可以考虑把文字放到 cover-view 上, 它也是一种原生组件,可以覆盖在 canvas 上的。具体的可以参考小程序官方文档 原生组件说明

    关于2018踩的坑就写到这里了,当然还有一些其他的,暂时没有时间整理,下次如果整理后,再写一篇补充一下。

    如果大家有什么问题,或者过去踩到过了哪些坑,欢迎在评论区讨论哈。

  • 相关阅读:
    UVALive 5983 MAGRID DP
    2015暑假训练(UVALive 5983
    poj 1426 Find The Multiple (BFS)
    poj 3126 Prime Path (BFS)
    poj 2251 Dungeon Master 3维bfs(水水)
    poj 3278 catch that cow BFS(基础水)
    poj3083 Children of the Candy Corn BFS&&DFS
    BZOJ1878: [SDOI2009]HH的项链 (离线查询+树状数组)
    洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
    洛谷P3065 [USACO12DEC]第一!First!(Trie树+拓扑排序)
  • 原文地址:https://www.cnblogs.com/yugege/p/10279990.html
Copyright © 2011-2022 走看看