CSS的BFC和Vue里的一个函数

336 阅读3分钟

云中的神啊,雾中的仙,神姿仙态桂林的山。这首诗是小时候背过的《桂林山水歌》。

前情回顾

上篇文章聊了下vue源码中的生命周期。有时候我觉的看源码其实是在浪费时间,今天聊一下css中的BFC和今天看的Vue里的一个比较有意思的函数。

BFC(block format context) 块儿格式化上下文

块元素布局过程的区域,也是浮动元素与其他元素交互的区域。可以理解为设置块元素属性的过程。从如何创建bfc来看,bfc的过程主要发生在块元素布局的过程

什么样的操作会创建BFC?

  • 根元素html
  • 使用浮动float
  • 使用绝对定位position:absuote|fixed
  • 使用行内块display:inline-block
  • 使用overflow
  • 使用display:flow-root
  • 弹性布局display:flex|inline-flex
  • 网格布局display:grid|inline-grid
  • 表格布局display:table|table-cell

BFC相关的Bug

  • 浮动元的父元素高度塌陷 处理这个问题通常是给父元素加一个overflow。overflow会创建一个新的BFC,将子元素包含进去。

    另外一个方法是使用display:flow-root。它可以创建无副作用的BFC,中的所有内容都会参与 BFC,浮动的内容不会从底部溢出。

  • 外边距重合

CSS如何工作?

  • 浏览器载入HTML
  • html转为DOM,DOM是文件在计算机内存中的表现形式。
  • 浏览器会拉取该HTML相关的大部分资源,比如嵌入到页面的图片、视频和CSS样式。
  • 拉取到css之后进行解析。基于选择器规则
  • 渲染树进行布局
  • 展示到网页上

当css遇到无法解析的属性或值时,会忽略并继续执行下一个解析

CSS shape 形状

css 其实是可以直接设置形状的。这个有一篇文章写得非常好。回头我找一下看看。

隐藏元素的六种方法

  • display:none
  • vusibility:hidden
  • opacity:0
  • clip-path:inset(100%)
  • html的hidden属性
  • html的aria-hidden属性
/*******************************************************************************\
 *                                                                             *
 * Visually hide any element (mostly text) accessibly.                         *
 * Support includes IE9+                                                       *
 * Source: https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html   *
 *                                                                             *
 *******************************************************************************/

.sr-only {
    clip: rect(0 0 0 0);
    clip-path: inset(100%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap; 
    width: 1px;
}

display:nonevusibility:hidden会将元素从dom中移除,尽量不使用。

那个有意思的函数generateCodeFrame

src/complier/codeframe.js


const range = 2

export function generateCodeFrame (
  source: string,
  start: number = 0,
  end: number = source.length
): string {
  const lines = source.split(/\r?\n/)
  let count = 0
  const res = []
  for (let i = 0; i < lines.length; i++) {
    count += lines[i].length + 1
    if (count >= start) {
      for (let j = i - range; j <= i + range || end > count; j++) {
        if (j < 0 || j >= lines.length) continue
        res.push(`${j + 1}${repeat(` `, 3 - String(j + 1).length)}|  ${lines[j]}`)
        const lineLength = lines[j].length
        if (j === i) {
          // push underline
          const pad = start - (count - lineLength) + 1
          const length = end > count ? lineLength - pad : end - start
          res.push(`   |  ` + repeat(` `, pad) + repeat(`^`, length))
        } else if (j > i) {
          if (end > count) {
            const length = Math.min(end - count, lineLength)
            res.push(`   |  ` + repeat(`^`, length))
          }
          count += lineLength + 1
        }
      }
      break
    }
  }
  return res.join('\n')
}

function repeat (str, n) {
  let result = ''
  if (n > 0) {
    while (true) { // eslint-disable-line
      if (n & 1) result += str
      n >>>= 1
      if (n <= 0) break
      str += str
    }
  }
  return result
}

这个函数会将接受到的source字符串按照回车键及换行符分割。然后生成一个字符串模板。比如你在文件里写的代码是:

  <template>
    <div>测试</div>
  </template>

它会返回一个类似的

1  |  <template>
   |  ^^^^^^^^^^
2  |          <div>测试</div>
   |  ^^^^^^^^^^^^^^^^^^^^^
3  |        </template>
   |  ^^^^^^^^^^^^^^^^^

如果你写的是js代码:

  function test() {
    console.log('test')
  }

它会返回一个类似的:

1  |  function test() {
   |  ^^^^^^^^^^^^^^^^^
2  |          console.log('test')
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3  |        }
   |  ^^^^^^^

刚开始我一直在想找个函数有什么用,似乎确实是没啥用。然后我找到了如下代码:

 // check compilation errors/tips
    if (process.env.NODE_ENV !== 'production') {
      if (compiled.errors && compiled.errors.length) {
        if (options.outputSourceRange) {
          compiled.errors.forEach(e => {
            warn(
              `Error compiling template:\n\n${e.msg}\n\n` +
              generateCodeFrame(template, e.start, e.end),
              vm
            )
          })
        } else {
          warn(
            `Error compiling template:\n\n${template}\n\n` +
            compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
            vm
          )
        }
      }
  
    }

说明这个generateCodeFrame是为了在编译出错的时候给出相应的提示。

总结

BFC块儿格式化上下文,其实是块儿元素尤其是块元素在布局过程中衍生出来的一个概念。而重点是元素布局的常见方法,浮动、定位、弹性、网格。

而对于这个函数,在我们的代码编译出错时,控制台及页面上的错误信息就是这个函数的返回结果。

最后说两句

  1. 动一动您发财的小手,「点个赞吧」
  2. 动一动您发财的小手,「点个在看」
  3. 都看到这里了,不妨 「加个关注」
  4. 不妨 「转发一下」,好东西要记得分享

公众号:JavaScript高级程序设计