博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Element源码分析系列2-Container(布局容器)
阅读量:5746 次
发布时间:2019-06-18

本文共 2872 字,大约阅读时间需要 9 分钟。

简介

所谓布局容器,就是页面的整体结构,一般来说就是<header>,<footer>,<aside>,<main>等构成的页面总体架构,官网的示例图如下

Element的处理是最外层有一个
container容器,里面才是上面4个子组件且只能是上面4个之一,下面依次分析每个组件的源码

Container组件

顾名思义,它是一个容器组件,承载子组件,容器组件应该有什么样的特性,无非就是块状,高度自适应等,Element加了一条规则:当子元素中包含 <el-header><el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列,这是不是很神奇,下面上代码来探究一下原理,代码

复制代码

这就是一个典型的单文件vue组件形式,只不过样式部分被分离出去了,首先来看template部分,发现其实就是<section>的封装而已,后面的组件也都采用了利于SEO的语义化tag标签而不是div,其实它们本质上就是块状元素,功能和div是一样的,注意<section>里面的<slot>,这就是承载子组件的插槽,如果不写则将会没有任何子元素,且是一个匿名插槽,接下来我们来看样式,el-container这个类

@import "mixins/mixins";@include b(container) {  display: flex;  flex-direction: row;  flex: 1;  flex-basis: auto;  box-sizing: border-box;  min-width: 0;  @include when(vertical) {    flex-direction: column;  }}复制代码

可以看出<section>其实是flex布局,且默认方向为横向,其中flex-basis:auto设置其基准长度为自适应,这里的flex:1表示如果container被父container包围,那么它会分配剩余的宽或高

然后我们来看js部分,isVertical是一个计算属性,首先判断是否有direction属性,如果有则直接返回水平还是垂直方向布局,如果没有则通过判断子元素来确定布局方向,重点就是这里的代码了

isVertical() {    ...    return this.$slots && this.$slots.default      ? this.$slots.default.some(vnode => {        const tag = vnode.componentOptions && vnode.componentOptions.tag;        return tag === 'el-header' || tag === 'el-footer';      })      : false;}复制代码

它是一个3元运算符,首先判断this.$slots&& this.$slots.default,如果不存在直接返回false,不存在的情况就是子元素为空。this.$slots是组件的实例属性,组件是可复用的Vue的实例,和 new Vue()一样是实例,因此有以下属性

所以
this.$slots.default返回了所有没有被包含在具名插槽中的子元素,如果这些子元素存在,那么开始依次遍历这些子元素,注意
some高阶函数的使用,这里就是要在所有子元素中查看是否存在
<el-header>或者
<el-footer>,
some所遍历的数组只要有一个为true,则整体返回true,否则为false,而
every则是要所有都是true才返回true,这里的高阶函数简化了代码量,如果用一般的for循环显得不那么优雅

接下来是如何判断子元素是<el-header>或者<el-footer>,这里首先要明确this.$slots.default是个数组,里面的每个元素都是一个VNodeVNode是虚拟dom中的虚拟节点,当组件被编译时,每个<...>就会生成一个虚拟的节点,大致结构如下图

、 拥有tag,childern,text等属性,而
componentOptions里面才包含元素的tag名称,注意VNode的tag不是我们想要的,进入Vue源码查找相关代码

const vnode = new VNode(    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,    data, undefined, undefined, undefined, context,    { Ctor, propsData, listeners, tag, children },    asyncFactory  )复制代码

发现第一个参数就是tag,其实是有前缀的,而componentOptions{ Ctor, propsData, listeners, tag, children }这么个对象,代表组件选项属性,这里面的tag才是我们想要的,打印出VNode证明了上面的说法

因此这里给我们一个怎么判断子元素类型的一个启发方法,可以借鉴。综上,这个计算属性的函数就能够通过子元素来判断自身flex的布局方向了

Footer组件

由于剩下的组件都很相似,这里就分析一个Footer,代码如下

复制代码

由此可见仍然是封装了原生的<footer>,并有一个默认高度,footer本质上就是一个块状元素而已,下面来查看scss代码

@import "mixins/mixins";@import "common/var";@include b(footer) {  padding: $--footer-padding;  box-sizing: border-box;  flex-shrink: 0;}复制代码

注意flex-shrink:0这个代码,这表示当父容器宽度不够时,footer不会收缩而是保持原本的宽度,也就是说footer是永远不会被压缩,就算超出容器。flex-shrink默认为1,也就是所有元素等比例收缩,对于下图这种形式的布局

其中header和footer的
flex-shrink都是0,也就是不会压缩,而main中的代码
flex:1表示了只有main会被压缩或者扩张,flex:1是
flex:grow:1,flex:shrink:1,flex-basis:auto的简写,又因为
flex:grow默认值为0,所以只有main会被压缩或扩张,header和footer都不变

总结

综上,整个布局其实就是对原生的封装,主要就是container的处理,如果浏览器不支持flex,则上述布局无效

转载地址:http://djazx.baihongyu.com/

你可能感兴趣的文章
F#初学笔记06
查看>>
实战:将企业域名解析委派给企业DNS服务器
查看>>
在Lync 2013环境部署Office Web Apps
查看>>
微软大会Ignite,你准备好了么?
查看>>
读书笔记-高标管事 低调管人
查看>>
Master带给世界的思考:是“失控”还是进化
查看>>
用户和开发者不满苹果iCloud问题多多
查看>>
java.lang.UnsatisfiedLinkError:no dll in java.library.path终极解决之道
查看>>
我的工具:文本转音频文件
查看>>
【许晓笛】从零开始运行EOS系统
查看>>
【跃迁之路】【460天】程序员高效学习方法论探索系列(实验阶段217-2018.05.11)...
查看>>
C++入门读物推荐
查看>>
TiDB 源码阅读系列文章(七)基于规则的优化
查看>>
面试中会遇到的正则题
查看>>
Spring之旅第八站:Spring MVC Spittr舞台的搭建、基本的控制器、请求的输入、表单验证、测试(重点)...
查看>>
数据结构与算法——常用排序算法及其Java实现
查看>>
你所不知的Webpack-多种配置方法
查看>>
React.js 集成 Kotlin Spring Boot 开发 Web 应用实例详解
查看>>
webpack+typescript+threejs+vscode开发
查看>>
python读excel写入mysql小工具
查看>>