Привет всем, я Лин Сансинь. О, мы, должно быть, столкнулись со многими библиотеками пользовательского интерфейса, когда работали над Vue. Среди них ElementUI должен быть наиболее используемым! Спустя столько времени, разве ты не хочешь знать, как он этого добился? Это как если бы вы были с девушкой в течение долгого времени, и если она вам нравится, вы, естественно, захотите узнать о ней много.Если вы не возьмете на себя инициативу спросить, как она может вам сказать? ? ? Давайте посмотрим на исходный код ElementUI. Ух!
скачать
Скачать Gayhub (исходная версия)
Каждый в гейхабе может сделать клон
Скопируйте прямо в node_module вашего собственного проекта (релизная версия)
Да, я был в этом экземпляре, готов хе-хе
Анализ каталога
Потому что я в основном смотрю исходники в каталоге пакетов, на самом деле любую версию можно узнать, я использую релизную версию.
/ 发布版本包目录结构
element-ui
├── lib // 打包后文件目录
├── packages // 组件的源码目录 (主要学习)
├── alert // 具体组件源码包
├── src // Vue组件包
├── index.js // 入口文件
├── src // 源码目录
├── directive // 实现滚轮优化,鼠标点击优化
├── locale // i18n国际化
├── mixins // Vue混合器
├── transition // 样式过渡效果
├── utils // 工具类包
├── index.js // 源码入口文件
├── types // typescript文件包
├── package.json // npm包核心文件
Представление документации ElementUI
Компонентный анализ
el-row
завернутыйel-col
, чтобы добиться эффекта «ряда» и «столбца». Братья пользовались, все понимают.
Параметры эл-ряда
Параметры эл-кол
порыв! ! ! Давай сделаем это! ! !
Здание каталога
Я использовал каркас, который построил сам, чтобы изучить исходный код ElementUI. Братья могут выбрать создание собственного каркаса или использовать Vuecli для непосредственного обучения. В Nuggets есть много статей о «построении лесов». найти один. Ища его, вы можете напрямую скопировать исходный код для стиля. Здесь мы обсуждаем только аспект JavaScript.
el-row имитирует анализ исходного кода
// 文件 row / src / Row.js 中
export default {
name: 'CRow',
props: {
gutter: { // 栅格间隔
type: Number,
default: 0,
},
type: String, // 布局模式,可选flex,现代浏览器下有效
justify: { // flex布局下的水平排列方式
type: String,
default: 'start',
},
align: { // flex布局下的垂直排列方式
type: String,
default: 'top',
},
tag: { // 自定义元素标签(涉及到vue的render函数里的createElement)
type: String,
default: 'div', // 默认是div标签
},
},
created() {
console.log(this.$slots, this.$slots.default.length, 'slots') // 想看看$slot长啥样,你们可以忽略
},
computed: {
getRowGutterStyle() { // 计算左右margin,配合gutter计算
if (this.gutter === 0) return ''
const value = this.gutter / 2 + 'px'
return {
marginLeft: value,
marginRight: value,
}
},
getRowFlexClass() { // 计算出flex布局的class是哪些
return [
{ 'c-row-flex': this.type === 'flex' },
this.justify === 'start' ? '' : `is-justify-${this.justify}`,
this.align === 'top' ? '' : `is-align-${this.align}`,
]
},
},
render: function (createElement) { // 渲染dom的函数render
return createElement(this.tag, { // 利用createElement创建dom
class: [
'c-row',
{ 'c-row-flex': this.type === 'flex' },
this.justify === 'start' ? '' : `is-justify-${this.justify}`,
this.align === 'top' ? '' : `is-align-${this.align}`,
],
style: this.getRowGutterStyle
}, this.$slots.default)
},
}
// 文件 row / index.js 中
import CRow from './src/Row.js'
CRow.install = function (Vue) { // 为什么要有install方法,下文会讲
Vue.component(CRow.name, CRow) // 全局注册组件
}
export default CRow
el-col имитирует анализ исходного кода
// 文件 col / src / Col.js中
export default {
name: 'CCol',
props: {
span: { // 栅格占据的列数
type: Number,
default: 24,
},
offset: { // 栅格左侧的间隔格数
type: Number,
default: 0,
},
// scss的for循环函数 + 媒体查询 可以实现以下效果
xs: [Number, Object],// <768px 响应式栅格数或者栅格属性对象
sm: [Number, Object],// ≥768px 响应式栅格数或者栅格属性对象
md: [Number, Object],// ≥992px 响应式栅格数或者栅格属性对象
lg: [Number, Object],// ≥1200px 响应式栅格数或者栅格属性对象
xl: [Number, Object],// ≥1920px 响应式栅格数或者栅格属性对象
tag: { // 自定义元素标签(涉及到vue的render函数里的createElement)
type: String,
default: 'div' // 默认是div标签
}
},
computed: {
getColGutterStyle() {
const gutter = this.$parent.gutter // 因为el-row是包在el-row里的,所以想要计算每个栅格之间的间隔需要从外层的el-row获取gutter计算padding
if (this.gutter === 0) return ''
const value = gutter / 2 + 'px'
return {
paddingLeft: value,
paddingRight: value,
}
},
getColOffsetClass() { // 根据offset计算每一栅格向左的间隔
if (this.offset === 0) return ''
return 'c-col-offset-' + this.offset
},
getColMediaClass() { // 计算响应式的class
let sizeArr = [];
['xs', 'xm', 'md', 'lg', 'xl'].forEach((size) => {
if (typeof this[size] === 'number') { // 判断传进来了哪个响应式宽度,并计算出class名,保存在数组中
sizeArr.push(`c-col-${size}-${this[size]}`)
}
})
return sizeArr
},
},
render: function (createElement) { // render函数渲染dom
return createElement(this.tag, { // createElement函数创建dom
class: ['c-col', 'c-col-' + this.span, this.getColOffsetClass, ...this.getColMediaClass], // 动态class绑定
style: this.getColGutterStyle // 动态style绑定
}, this.$slots.default) // 默认插槽
},
}
// 文件 col / index.js 中
import CCol from './src/Col.js'
CCol.install = function (Vue) { // 为什么要有install方法,下文会讲
Vue.component(CCol.name, CCol) // 全局注册组件
}
export default CCol
// style / row.scss 文件中
// 生成 c-col-1 到 c-col-24
@for $i from 1 through 24 {
.c-col-#{$i} {
width: 100%/24 * $i;
}
}
// 生成 c-col-offset-1 到 c-col-offset-24
@for $i from 1 through 24 {
.c-col-offset-#{$i} {
margin-left: 100%/24 * $i;
}
}
.c-col {
display: inline-block;
box-sizing: border-box;
}
@media screen and (max-width: 767px) {
@for $i from 1 through 24 {
.c-col-xs-#{$i} {
width: 100%/24 * $i;
}
}
}
@media screen and (min-width: 768px) {
@for $i from 1 through 24 {
.c-col-sm-#{$i} {
width: 100%/24 * $i;
}
}
}
@media screen and (min-width: 992px) {
@for $i from 1 through 24 {
.c-col-md-#{$i} {
width: 100%/24 * $i;
}
}
}
@media screen and (min-width: 1200px) {
@for $i from 1 through 24 {
.c-col-lg-#{$i} {
width: 100%/24 * $i;
}
}
}
@media screen and (min-width: 1920px) {
@for $i from 1 through 24 {
.c-col-xl-#{$i} {
width: 100%/24 * $i;
}
}
}
использовать компоненты
// 主入口文件main.js中引入
import '../package/styles/index.scss' // 引入总样式
import { CButton, CButtonGroup, CRow, CCol, CContainer,
CHeader, CFooter, CAside, CMain, CBacktop, CCard } from '../package/index' // 解构引入
Vue.use(CButton)
Vue.use(CButtonGroup)
Vue.use(CRow) // 这就是为什么要导出一个install方法
Vue.use(CCol) // 这就是为什么要导出一个install方法
Vue.use(CContainer)
Vue.use(CHeader)
Vue.use(CFooter)
Vue.use(CAside)
Vue.use(CMain)
Vue.use(CBacktop)
Vue.use(CCard)
Затем его можно использовать глобально
<template>
<div class="demo-layout">
<c-row :gutter="20">
<c-col :span="24"
><div class="item">{{ doubleNum }}</div></c-col
>
</c-row>
<c-row :gutter="20">
<c-col :span="12"> <div class="item">hhh</div></c-col>
<c-col :span="12"><div class="item">hhh</div></c-col>
</c-row>
<c-row :gutter="20">
<c-col :span="8"><div class="item">hhh</div></c-col>
<c-col :span="8"><div class="item">hhh</div></c-col>
<c-col :span="8"><div class="item">hhh</div></c-col>
</c-row>
<c-row :gutter="20">
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
</c-row>
<c-row :gutter="20">
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6" :offset="12"><div class="item">hhh</div></c-col>
</c-row>
<c-row type="flex" justify="end">
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
</c-row>
<c-row type="flex" justify="space-around">
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
</c-row>
<c-row type="flex" justify="space-between">
<c-col :span="6"><div class="item">hhh</div></c-col>
<c-col :span="6"><div class="item">hhh</div></c-col>
</c-row>
<c-row :gutter="10">
<c-col :xs="8" :sm="6" :md="1" :lg="6" :xl="1"><div class="item">hhh</div></c-col>
<c-col :xs="4" :sm="6" :md="1" :lg="6" :xl="11"><div class="item">hhh</div></c-col>
<c-col :xs="4" :sm="6" :md="12" :lg="11" :xl="11"><div class="item">hhh</div></c-col>
<c-col :xs="8" :sm="6" :md="10" :lg="1" :xl="1"><div class="item">hhh</div></c-col>
</c-row>
<c-row :gutter="10" tag="header">
<c-col tag="p" :xs="8" :sm="6" :md="1" :lg="6" :xl="1"><div class="item">hhh</div></c-col>
<c-col :xs="4" :sm="6" :md="1" :lg="6" :xl="11"><div class="item">hhh</div></c-col>
<c-col :xs="4" :sm="6" :md="12" :lg="11" :xl="11"><div class="item">hhh</div></c-col>
<c-col :xs="8" :sm="6" :md="10" :lg="1" :xl="1"><div class="item">hhh</div></c-col>
</c-row>
</div>
</template>
Зачем экспортировать метод установки и какое отношение он имеет к методу использования Vue
Короче говоря,
Vue.use(options)
, выполнитoptions
серединаinstall
свойства, то естьinstall
функция, которая экспортирует один вышеinstall
Функция, функция содержит код для регистрации глобального компонента, поэтому, если вы хотите, чтобы Vue мог использоватьuse
метод, вы должны убедиться, что экспортируемый вами объект опций содержит метод установки
суммировать
Код набирается один за другим, но если вы не можете его напечатать, просто отпустите его, вы должны чему-то научиться, иначе будет бесполезно, если вы наберете код! Вот что я узнал нового (нового для меня), имитируя компонент макета ElementUI.
-
scss
середина@for
использование метода - Дочерний компонент получает данные от родительского компонента, используя
this.$parent
Получать -
Vue.use(options)
Будет выполнятьoptions
изinstall
функция -
$slots
является объектом,key
дляslot-name
,value
соответствующий элемент (массив), по умолчаниюkey
даdefault