【ElementPlus源码】Container 布局容器

文章目录

    • index.ts
    • Container
    • header
    • utils
      • withInstall
      • withNoopInstall
    • hooks
      • useNamespace
    • 单元测试

看源码时候做的笔记。如有错误请指出!
关于路径的省略,详见button:【ElementPlus源码】Button按钮-CSDN博客

index.ts

导入一堆组件,导出ElContainer。

import Container from './src/container.vue'
import Aside from './src/aside.vue'
import Footer from './src/footer.vue'
import Header from './src/header.vue'
import Main from './src/main.vue'export const ElContainer = withInstall(Container, {Aside,Footer,Header,Main,
})
... // 不全

Container

判断是否垂直,先判断props中的direction属性。

在这里插入图片描述
若没有props.direction,判断插槽中是否有header和footer,有则返回true,代表垂直。

const isVertical = computed(() => {if (props.direction === 'vertical') {return true} else if (props.direction === 'horizontal') {return false}//   是否有ElHeader或ElFooter组件,有就为trueif (slots && slots.default) {const vNodes: VNode[] = slots.default()return vNodes.some((vNode) => {const tag = (vNode.type as Component).namereturn tag === 'ElHeader' || tag === 'ElFooter'})} else {return false}
})

表示垂直的样式会绑定在style中:

<section :class="[ns.b(), ns.is('vertical', isVertical)]"><slot /></section>

useNamespace是一个hook,详情写在博客hooks/useNamespace下。它返回一个对象,可以生成规范的类名。

const ns = useNamespace('container')

ns.is('vertical', isVertical)生成的就是:isVertical

在这里插入图片描述

container只有direction属性。

header

header只有height属性,写在props中。style会计算height属性,最终将结果绑定到header上。

<template><header :class="ns.b()" :style="style"><slot /></header>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useNamespace } from '@element-plus/hooks'import type { CSSProperties } from 'vue'defineOptions({name: 'ElHeader',
})const props = defineProps({/*** @description height of the header*/height: {type: String,default: null,},
})const ns = useNamespace('header')
const style = computed(() => {return props.height? (ns.cssVarBlock({height: props.height,}) as CSSProperties): {}
})
</script>

aside、footer、main完全相似,不赘述。

utils

withInstall

传入一个main组件和extra,返回一个添加了install方法的main组件。
这个方法将main和extra中的所有属性注册到app中。

export const withInstall = <T, E extends Record<string, any>>(main: T, // 主要的 Vue 组件extra?: E // 可选的对象,其属性值是其他 Vue 组件
) => {/* 给 `main` 组件添加一个 `install` 方法这个方法接受一个 Vue 应用作为参数并将 `main` 组件以及 `extra` 中的所有组件注册到这个应用中*/;(main as SFCWithInstall<T>).install = (app): void => {for (const comp of [main, ...Object.values(extra ?? {})]) {app.component(comp.name, comp)}}//   将extra的属性添加到main上if (extra) {for (const [key, comp] of Object.entries(extra)) {;(main as any)[key] = comp}}// SFCWithInstall<T>表示带有 `install` 方法的 Vue 单文件组件// `E` 是 `extra` 的类型。return main as SFCWithInstall<T> & E
}

container/index.ts中调用:

返回了一个对象ElContainer ,有一个install方法,若调用install方法,则将Container、Aside、Footer、Header、Main五个组件注册到app上,并可以通过ElContainer.Container的方法访问Container。

export const ElContainer = withInstall(Container, {Aside,Footer,Header,Main,
})

withNoopInstall

创建一个带有空操作 install 方法的 Vue 组件对象

export const withNoopInstall = <T>(component: T) => {;(component as SFCWithInstall<T>).install = NOOPreturn component as SFCWithInstall<T>
}

关于NOOP:

import { NOOP } from '@vue/shared'

NOOP 是一个常见的编程术语,代表 “No Operation”,即不执行任何操作。在许多编程语言和环境中,它通常被用作一个占位符函数,当你需要一个函数但又不希望它做任何事情时,可以使用NOOP。

调用withNoopInstall:

export const ElAside = withNoopInstall(Aside)

hooks

useNamespace

路径:hooks/use-namespace

用于生成 BEM(Block Element Modifier)命名规则的类名和 CSS 变量名.

BEM 是一种 CSS 命名方法,全称是 Block Element Modifier,即块(Block)、元素(Element)、修饰符(Modifier)。

下面代码接受两个参数:块名和可选的命名空间覆盖。

返回一个对象,包含属性如下:

  • namespace:命名空间。
  • b、e、m、be、em、bm 和 bem:用于生成不同类型的 BEM 类名的函数。
  • is:用于生成状态类名的函数。
  • cssVar、cssVarName、cssVarBlock 和 cssVarBlockName:用于生成 CSS 变量名的函数。
const statePrefix = 'is-'const _bem = (namespace: string,block: string,blockSuffix: string,element: string,modifier: string
) => {let cls = `${namespace}-${block}`if (blockSuffix) {cls += `-${blockSuffix}`}if (element) {cls += `__${element}`}if (modifier) {cls += `--${modifier}`}return cls
}export const useNamespace = (block: string,namespaceOverrides?: Ref<string | undefined>
) => {const namespace = useGetDerivedNamespace(namespaceOverrides)const b = (blockSuffix = '') =>_bem(namespace.value, block, blockSuffix, '', '')const e = (element?: string) =>element ? _bem(namespace.value, block, '', element, '') : ''const m = (modifier?: string) =>modifier ? _bem(namespace.value, block, '', '', modifier) : ''const be = (blockSuffix?: string, element?: string) =>blockSuffix && element? _bem(namespace.value, block, blockSuffix, element, ''): ''const em = (element?: string, modifier?: string) =>element && modifier? _bem(namespace.value, block, '', element, modifier): ''const bm = (blockSuffix?: string, modifier?: string) =>blockSuffix && modifier? _bem(namespace.value, block, blockSuffix, '', modifier): ''const bem = (blockSuffix?: string, element?: string, modifier?: string) =>blockSuffix && element && modifier? _bem(namespace.value, block, blockSuffix, element, modifier): ''const is: {(name: string, state: boolean | undefined): string(name: string): string} = (name: string, ...args: [boolean | undefined] | []) => {const state = args.length >= 1 ? args[0]! : truereturn name && state ? `${statePrefix}${name}` : ''}// for css var// --el-xxx: value;const cssVar = (object: Record<string, string>) => {const styles: Record<string, string> = {}for (const key in object) {if (object[key]) {styles[`--${namespace.value}-${key}`] = object[key]}}return styles}// with blockconst cssVarBlock = (object: Record<string, string>) => {const styles: Record<string, string> = {}for (const key in object) {if (object[key]) {styles[`--${namespace.value}-${block}-${key}`] = object[key]}}return styles}const cssVarName = (name: string) => `--${namespace.value}-${name}`const cssVarBlockName = (name: string) =>`--${namespace.value}-${block}-${name}`return {namespace,b,e,m,be,em,bm,bem,is,// csscssVar,cssVarName,cssVarBlock,cssVarBlockName,}
}

省流版:返回一个对象,可以生成规范的类名。

单元测试

单元测试写的很好啊,可以做学习单元测试的例子:

container.test.tsx:

const AXIOM = 'Rem is the best girl'describe('Container.vue', () => {test('container render test', async () => {const wrapper = mount(() => <Container>{AXIOM}</Container>)expect(wrapper.text()).toEqual(AXIOM)})test('vertical', () => {const wrapper = mount(() => (<Container><Header /><Main /></Container>))expect(wrapper.classes('is-vertical')).toBe(true)})test('direction', () => {const wrapper = mount({data: () => ({ direction: 'horizontal' }),render() {return (<Container direction={this.direction}><Header /><Main /></Container>)},})expect(wrapper.vm.$el.classList.contains('is-vertical')).toBe(false)wrapper.vm.direction = 'vertical'wrapper.vm.$nextTick(() => {expect(wrapper.vm.$el.classList.contains('is-vertical')).toBe(true)})})
})describe('Header', () => {test('create header', () => {const wrapper = mount(() => <Header />)expect(wrapper.classes()).toContain('el-header')})test('header height', () => {const wrapper = mount(() => <Header height="100px" />)const vm = wrapper.vmexpect(getCssVariable(vm.$el, '--el-header-height')).toEqual('100px')})
})describe('Aside', () => {test('aside create', () => {const wrapper = mount(() => <Aside />)expect(wrapper.classes()).toContain('el-aside')})test('aside width', () => {const wrapper = mount(() => <Aside width="200px" />)const vm = wrapper.vmexpect(getCssVariable(vm.$el, '--el-aside-width')).toEqual('200px')})
})describe('Main', () => {test('main create', () => {const wrapper = mount(() => <Main />)expect(wrapper.classes()).toContain('el-main')})
})describe('Footer', () => {test('footer create', () => {const wrapper = mount(() => <Footer />)expect(wrapper.classes()).toContain('el-footer')})test('footer height', () => {const wrapper = mount(() => <Footer height="100px" />)const vm = wrapper.vmexpect(getCssVariable(vm.$el, '--el-footer-height')).toEqual('100px')})
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/862750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

003-GeoGebra如何无缝嵌入到PPT里

GeoGebra无缝嵌入到PPT里真是一个头疼的问题&#xff0c;已成功解决&#xff0c;这里记录一下&#xff0c;希望可以帮助到更多人。 注意&#xff0c;后续所有的文章说的PPT都是Offce Power Point, 不要拿着WPS的bug来问我哦&#xff0c;我已经戒WPS了&#xff08;此处表示无奈&…

Vue组件化、单文件组件以及使用vue-cli(脚手架)

文章目录 1.Vue组件化1.1 什么是组件1.2 组件的使用1.3 组件的名字1.4 嵌套组件 2.单文件组件2.1 vue 组件组成结构2.1.1 template -> 组件的模板结构2.1.2 组件的 script 节点2.1.3 组件的 style 节点 2.2 Vue组件的使用步骤2.2.1 组件之间的父子关系2.2.2 使用组件的三个步…

直播电商APP源码

你有没有想过&#xff0c;如何通过手机就能够触手可及地购买到你想要的商品呢?直播电商APP源码&#xff0c;为你带来了全新的购物体验。它不仅为用户提供了便捷快速的购物平台&#xff0c;还为商家提供了一个高效的销售渠道。 武汉迅狐科技有限公司研发的直播电商APP源码&…

Python | Leetcode Python题解之第190题颠倒二进制位

题目&#xff1a; 题解&#xff1a; class Solution:# param n, an integer# return an integerdef reverseBits(self, n):n (n >> 16) | (n << 16);n ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);n ((n & 0xf0f0f0f0) >&g…

virtualbox安装win10

等到安装完成 设备下选择安装增强功能

AUTOSAR NvM模块(一)

NvMBlockDescriptor [ECUC_NVM_00061] 用于存储所有特定于块的配置参数的容器。对于每个非易失性随机存取存储器&#xff08;NVRAM&#xff09;块&#xff0c;应该指定这个容器的一个实例。 NvMBlockCrcType 定义了NVRAM块的CRC数据宽度。根据Autosar标准&#xff0c;此参数…

Web渗透-逻辑漏洞

一、概述 逻辑漏洞是指由于程序逻辑不严或逻辑太复杂&#xff0c;导致一些逻辑分支不能够正常处理或处理错误&#xff0c;一般出现任意密码修改&#xff08;没有旧密码验证&#xff09;,越权访问&#xff0c;密码找回&#xff0c;交易支付金额等。对常见的漏洞进行过统计&…

2毛钱不到的2A同步降压DCDC电压6V频率1.5MHz电感2.2uH封装SOT23-5芯片MT3520B

前言 2A&#xff0c;2.3V-6V输入&#xff0c;1.5MHz 同步降压转换器&#xff0c;批量价格约0.18元 MT3520B 封装SOT23-5 丝印AS20B5 特征 高效率&#xff1a;高达 96% 1.5MHz恒定频率操作 2A 输出电流 无需肖特基二极管 2.3V至6V输入电压范围 输出电压低至 0.6V PFM 模式可在…

TS_开发一个项目

目录 一、编译一个TS文件 1.安装TypeScript 2.创建TS文件 3.编译文件 4.用Webpack打包TS ①下载依赖 ②创建文件 ③启动项目 TypeScript是微软开发的一个开源的编程语言&#xff0c;通过在JavaScript的基础上添加静态类型定义构建而成。TypeScript通过TypeScript编译器或…

我在高职教STM32——时钟系统与延时控制(1)

大家好&#xff0c;我是老耿&#xff0c;高职青椒一枚&#xff0c;一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次&#xff0c;同行应该都懂的&#xff0c;老师在课堂上教学几乎是没什么成就感的。正因如此&#xff0c;才有了借助 CSDN 平台寻求认同感和成就…

6.26.4.3 条件生成对抗和卷积网络用于x射线乳房质量分割和形状分类

一种基于条件生成对抗网络(conditional Generative Adversarial Networks, cGAN)的乳房肿块分割方法。假设cGAN结构非常适合准确地勾勒出质量区域&#xff0c;特别是当训练数据有限时。生成网络学习肿瘤的内在特征&#xff0c;而对抗网络强制分割与基础事实相似。从公开DDSM数据…

【语言模型】深入探索语言模型中的神经网络算法:原理、特点与应用

随着人工智能技术的飞速发展&#xff0c;神经网络算法在语言模型中的应用日益广泛&#xff0c;为自然语言处理领域带来了革命性的变革。本文将深入探讨当前语言模型中常用的几种神经网络算法&#xff0c;包括全连接神经网络、卷积神经网络、循环神经网络、长短期记忆网络、门控…

五线谱与简谱有什么区别 五线谱简谱混排怎么打 吉他谱软件哪个好

五线谱与简谱作为音乐记谱领域的两大主流系统&#xff0c;各自承载着深厚的历史渊源与独特的表现力&#xff0c;并在全球范围内被不同程度地接受和应用。尽管两者都是为了记录音乐作品中的音高和节奏信息&#xff0c;但其内在机制、适用范围以及学习曲线存在显著差别。下面我们…

版本控制系统:Git

基本操作 ctrl上行键&#xff1a;上次代码 本地仓库&#xff1a;Git init 新建文件&#xff1a;touch xxxx.xxx 查看状态&#xff1a;Git status 文件从工作区——暂存区&#xff1a;Git add ./文件名(.是通配符代表所有) 暂存区——仓库&#xff1a;Git commit -m &…

Spring企业开发核心框架-上

一、框架前言 1、总体技术体系 单一架构 一个项目&#xff0c;一个工程&#xff0c;导出为一个war包&#xff0c;在一个Tomcat上运行。也叫all in one. 单一架构&#xff0c;项目主要应用技术框架为&#xff1a;Spring&#xff0c;SpringMVC&#xff0c;Mybatis等 分布式架构…

vue-cil搭建项目

目录 一、使用 HbuilderX 快速搭建一个 vue-cli 项目 1.需要的环境——Node.js 2.搭建Vue-cil项目 二、组件路由 1.安装vue-router 2.创建router目录 3.使用路由 4.在main.js中配置路由 vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个 vue 的项目模板&#xff1b;…

VsCode:配置TypeScript开发环境

一、前提 电脑已经安装了npm 何如安装npm&#xff0c;请点击查看Node.js、npm常用命令、安装多个node版本 提醒&#xff1a;下文讲解操作是在mac 系统进行的&#xff0c;TypeScript简称&#xff1a;ts 二、安装TypeScript 在终端里执行命令&#xff1a;npm install -g typescr…

1panel 搭建多个网站

1panel 部署多个网站&#xff0c;另外的域名&#xff0c;或无域端口搭建方法。 当我们已经部署好一个网站后&#xff0c;想再部署一个网站在我们的服务器上时&#xff0c; 步骤&#xff1a;&#xff08;另外的域名&#xff0c;部署在同一个服务器方法&#xff09; 运行环境里…

六、资产安全—信息分级资产管理与隐私保护(CISSP)

目录 1.信息分级 2.信息分级方法 3.责任的层级 4.资产管理 5.隐私数据管理角色 6.数据安全控制 7.数据保护方案 8.使用安全基线 六、资产安全—数据管理(CISSP): 五、身份与访问管理—身份管理和访问控制管理(CISSP): 1.信息分级 信息分级举列: 2.信息分级方…

K8S 角色/组件及部署方式的简单概述

1.宏观架构图 2.角色详情 2.1 Master(Controller Plane) 早期是叫 Master 节点&#xff0c;后期改名为 Controller Plane&#xff0c;负责整个集群的控制和管理 Master 不会干活的(当然你让它干也是会干的&#xff0c;涉及到污点容忍)&#xff0c;而是起到访问入口&#xff…