предисловие
Далее следует очень болезненное время! !
Сегодня я подробно проанализировал исходный код Select.Когда я увидел, что в исходном коде было 900 строк, я был совершенно ошарашен.Это исходный код, который я читал больше всего.Посмотрев его, я обнаружил, что есть в ней много знаний.Точка, есть 16 импортируемых модулей, которые содержат различные компоненты, миксины и служебные функции, поэтому ввиду ограниченного объема этой статьи, я планирую написать ее в двух частях, а именно:Шаблоны"а также"Глава метода», глава шаблона в основном анализирует шаблон Select и некоторые относительно простые атрибуты, а глава метода фокусируется на анализеmethods
В нем есть различные методы.Теперь давайте посмотрим, что делает компонент Select.Рекомендуется поставить лайк/избранное перед просмотром.
Использование и особенности
Чтобы понять компонент пользовательского интерфейса, вы должны сначала начать с его функции.Только после понимания конкретной функции компонента вы поймете, зачем его инкапсулировать? Как упаковать? существуетОфициальная документация ElementUIТам подробно описаны функции и методы, и те, кто не знаком с ним, могут сначала изучить его. Select в основном используется следующими способами:
- Основное использование: это основной раскрывающийся список, положение раскрывающегося списка будет выборочно отображаться выше или ниже в зависимости от размера пространства на странице.
- Отключить параметры: вы можете отключить параметр или весь раскрывающийся список.
- Кнопка очистки: Излишне говорить, что компонент ввода также имеет эту функцию.
- Множественный выбор: выберите несколько раскрывающихся параметров, выбранные параметры могут отображаться в виде тегов или объединяться в абзац.
- Пользовательские параметры раскрывающегося списка: параметры раскрывающегося списка могут быть пользовательскими стилями.
- Группировка: выпадающие параметры могут быть сгруппированы по определенным категориям
- Поиск: объедините с сервером, чтобы создать поисковые ассоциации.
- Создать запись: вы можете создать тег, набрав и отобразив его в поле ввода.
Видно, что функций Select очень много, и в основном учитываются все функции, которые нам нужно использовать в наших повседневных нуждах.Так как функций так много, инкапсулировать их должно быть очень хлопотно. все, 900 строк кода Написаны не зря! !
После уточнения функции нам очень полезно посмотреть исходный код, мы можем найти соответствующую реализацию кода по функции, а затем перейти непосредственно к исходному коду:
Базовая структура
el-select
Лучше не смотреть на структуру непосредственно в исходном коде, легко запутаться.Сначала давайте посмотрим на структуру HTML, отображаемую при самом простом использовании:
Из этой относительно простой структуры легко увидеть, что основная часть состоит из входных и суффиксных элементов.Теперь давайте по крупицам проанализируем структуру шаблона:Во-первых, самый внешний уровень — это класс с именемel-select
изdiv
, если объявленоsize
, также согласноsize
Добавить кel-select-size
класс, который обертываетel-select__tags
изdiv
, мы не будем рассматриватьtags
Похожие, посмотрите сначалаel-input
.
этоel-input
Рендеринг — это компонент ввода, инкапсулированный ElementUI. Если вы его еще не видели, вы можете сначала двигаться вперед.Сверхдетальный анализ исходного кода ElementUIВнимательно прочитайте входной исходный код.
<el-input>
<template slot="prefix" v-if="$slots.prefix">
<slot name="prefix"></slot>
</template>
<template slot="suffix">
<i v-show="!showClose" :class="['el-select__caret', 'el-input__icon', 'el-icon-' + iconClass]"></i>
<i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click="handleClearClick"></i>
</template>
</el-input>
Компонент ввода содержит два слота, префикс и суффикс.prefix
Слот используется для отображения содержимого заголовка компонента Select (если есть) иsuffix
Он используется для отображения пустой кнопки и маленькой стрелки за ней. Вы можете видеть, что здесь есть деталь, которая используется для маленьких стрелок.v-show
И кнопка очистки используетсяv-if
, вот краткое введение в разницу между ними:
- Оба работают для переключения отображения и скрытия элементов DOM.
-
v-show
Управляет элементами DOMdisplay: none
свойства, которые не изменяют структуру дерева DOM -
v-if
Управляет деревом DOM, напрямую добавляя или удаляя контролируемые элементы DOM. -
v-if
существует"Не отображается, когда начальное условие ложно", не начинает рендеринг, пока в первый раз не станет правдой -
v-if
Есть высшее"переключение накладных расходов",v-show
Есть высшее"Накладные расходы на начальный рендеринг" - то есть
v-show
Он подходит для частых манипуляций с DOM иv-if
Он используется, когда вы не часто манипулируете его структурой DOM.
События, вызванные им, также зарезервированы для следующего выпуска, чтобы проанализировать его вместе с вами. Не забудьте прочитать его вовремя.
Поскольку последняя структура использует много компонентов, которые ранее не встречались, сначала будут проанализированы компоненты, на которые ссылается Select.
el-select-menu
прежде всегоel-select-menu
, посмотрите на импортированные модули, чтобы увидеть, что использованиеselect-dropdown.vue
файл, зайди и посмотри. Структура этого компонента очень проста, есть только одинdiv
, который содержит слот, этоdiv
изclass
да"el-select-dropdown el-popper"
, он отображает на странице следующую структуру:
Вы можете видеть, что это структура раскрывающегося списка, который добавляется к узлу body черезposition
Он располагается над или под полем ввода и может регулироваться в соответствии с положением поля ввода. Сам по себе компонент не очень сложный, но он смешивается сvue-popper
, пока вvue-popper
повторно представлен вpopper-manager
,в то же времяvue-popper
Представлена сторонняя библиотека позиционированияpopper.js
, поэтому взаимосвязь здесь очень сложная, см. следующую картинку:
Давайте сначала поговорим о роли каждого модуля:
-
vue-popper
: Всплывающее окно для управления компонентами, когда создавать, где создавать, когда уничтожать и как уничтожать -
popup
В основном для открытия и закрытия всплывающего окна -
popup-manager
: используется для управления всеми модальными слоями на странице. -
popper.js
: сторонняя библиотека, в основном используемая для поиска всплывающего окна.
для
popper.js
Анализ относится кЭтот блог CSDN
Поскольку содержимое каждого модуля очень много, просто чтобы выбрать анализ и выбирать компоненты, связанные с ним, чтобы увидеть, если конкретно я могу быть местом проведенияgithubПосмотреть выше.
Вернемся снова к компоненту Select,el-select-menu
завернут вel-scrollbar
Чтобы содержимое раскрывающегося списка прокручивалось, следующее содержимоеel-scrollbar
анализ.
el-scrollbar
Давайте сначала посмотрим на входной файлindex.js
он импортируетScrollBar
даsrc/main
,этоel-scrollbar
Файл компонента, официалы сказали, что вся идея этого файла для справкиgemini-scrollbar, пошел сравнивать и обнаружил, что идея та же, даже нейминг тот же, но другие совместимы.
Файлы, импортированные сюда, в основном:
-
utils/resize-event.js
:resize
Привязка и отвязка событий -
utils/scrollbar-width.js
: Рассчитайте ширину полосы прокрутки -
toObject
: объединить все объекты в массиве в один объект -
Bar
: пользовательский компонент полосы прокрутки
main.js/render
Я проанализировал исходный код каждого файла, сначала посмотрите наmain.js
Внутри исходного кода:
// main.js
render(h) {
// 获取系统自带的滚动条的宽度
// scrollbarWidth() 看后文
let gutter = scrollbarWidth();
let style = this.wrapStyle;
// 如果滚动条存在
if (gutter) {
// 我觉得这地方应该是 `gutterWidth` 不过不重要了
const gutterWith = `-${gutter}px`;
const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};`;
if (Array.isArray(this.wrapStyle)) {
// toObject 看后文
style = toObject(this.wrapStyle);
style.marginRight = style.marginBottom = gutterWith;
} else if (typeof this.wrapStyle === 'string') {
style += gutterStyle;
} else {
style = gutterStyle;
}
}
// 这是最外层的 ul
const view = h(
this.tag,
{
class: ['el-scrollbar__view', this.viewClass],
style: this.viewStyle,
ref: 'resize'
},
// 子虚拟节点数组
this.$slots.default
);
// ul 外层包裹的 div
const wrap = (
<div
ref='wrap'
style={style}
onScroll={this.handleScroll}
class={[
this.wrapClass,
'el-scrollbar__wrap',
gutter ? '' : 'el-scrollbar__wrap--hidden-default'
]}
>
{[view]}
</div>
);
let nodes;
// 是否使用元素滚动条,默认是 false
// 使用自定义的 Bar 组件
if (!this.native) {
nodes = [
wrap,
<Bar move={this.moveX} size={this.sizeWidth}></Bar>,
<Bar vertical move={this.moveY} size={this.sizeHeight}></Bar>
];
} else {
nodes = [
<div
ref='wrap'
class={[this.wrapClass, 'el-scrollbar__wrap']}
style={style}
>
{[view]}
</div>
];
}
return h('div', { class: 'el-scrollbar' }, nodes);
},
Как видите, в основном используется прокручиваемая часть этого выпадающего списка.render
Функция рендеринга используется для построения DOM-структуры.Вся визуализированная структура показана на рисунке:
оli
Рендеринг этикетки выполняетсяel-option
Готово, анализировать позже. В функции рендеринга на внешний слойwrap
связалonscroll
событие, метод слушателя находится вmethods
Он определяет:
// onscroll 事件处理函数
handleScroll() {
const wrap = this.wrap;
// 计算出滚动条需要滚动的距离(百分比)
this.moveY = (wrap.scrollTop * 100) / wrap.clientHeight;
this.moveX = (wrap.scrollLeft * 100) / wrap.clientWidth;
},
Когда внутренний список прокручивается, рассчитайте расстояние, на которое должна прокручиваться полоса прокрутки, здесь используется процент, а затем вBar
组件里使用。 этоBar
Это официальный компонент пользовательской полосы прокрутки, который также анализируется ниже. Мы замечаем, что компонент получаетnative
Атрибут, этот атрибут указывает, использовать ли полосу прокрутки, которая поставляется с браузером, по умолчаниюfalse
То есть не использовать, а использоватьBar
компонент, затем поместите всю структуру вh
Оставьте это Vue для синтаксического анализа.
main.js/methods
methods
Определены два метода:
-
handleScroll
:onscroll
обработчик события -
update
: при срабатыванииresize
событие, изменить размер полосы прокрутки
update() {
// 宽高百分比
let heightPercentage, widthPercentage;
const wrap = this.wrap;
if (!wrap) return;
// 求出可视区域占内容总大小的百分比,这就是滚动条相对于内容的百分比
heightPercentage = (wrap.clientHeight * 100) / wrap.scrollHeight;
widthPercentage = (wrap.clientWidth * 100) / wrap.scrollWidth;
// 滚动条的大小
// 如果可视区域比内容总大小要小,证明需要滚动,把百分比赋值给 sizeXXX
// 如果不需要滚动 clientHeight = scrollHeight
this.sizeHeight = heightPercentage < 100 ? heightPercentage + '%' : '';
this.sizeWidth = widthPercentage < 100 ? widthPercentage + '%' : '';
}
Когда компонент раскрывающегося списка смонтирован, вызовитеupdate
метод, стоит отметить, что в компонентеprop
Одним из свойств являетсяnoresize
, это свойство запрещает изменение размера фрейма, официальный комментарий: «еслиcontainer
Размер не изменится, лучше настроить его на оптимизацию производительности». Оптимизированную производительность можно увидеть позже, а компонент вызывается до его монтирования и уничтожения.update
метод, который часто называютupdate
Будет потреблять определенное количество производительности, поэтому, когда мы не хотим изменять размер кадра, попробуйте объявитьnoresize
Атрибуты.
mounted() {
if (this.native) return;
// update 需要用到更新后的 DOM,所以放在 $nextTick 里
this.$nextTick(this.update);
// 如果可以调整框架的大小,就给元素添加一个 resize 监听事件
!this.noresize && addResizeListener(this.$refs.resize, this.update);
},
beforeDestroy() {
if (this.native) return;
// 移除元素的 resize 监听事件
!this.noresize && removeResizeListener(this.$refs.resize, this.update);
}
о
addResizeListener
Способ официальный - позаимствовать сторонний пакетresize-observer-polyfillиметь дело сresize
мероприятие,ResizeObserver
Это новый API с очень хорошей производительностью. Перейдите на MDN, чтобы узнать о нем.
Bar
Далее мы видимBar
Вызов компонента:
<Bar move={this.moveX} size={this.sizeWidth}></Bar>,
<Bar vertical move={this.moveY} size={this.sizeHeight}></Bar>
Передаются два или три аргумента:
-
move
: Расстояние для перемещения по горизонтали или вертикали -
size
: размер полосы прокрутки -
vertical
: Является ли это вертикальной полосой прокрутки, а не горизонтальной полосой прокрутки
dom.js/on
bar.js
файлBar
Компоненты, которые импортируют объекты двух классов инструментов.По поводу анализа классов инструментов я планирую написать специальную колонку позже.Здесь я кратко рассмотрю связанные методы.
/**
* 封装 on 方法给指定元素绑定事件
* @param {HTMLElement} element 要绑定事件的元素
* @param {String} event 要绑定的事件
* @param {Function} handler 事件触发时执行的函数
*/
export const on = (function() {
if (!isServer && document.addEventListener) {
return function(element, event, handler) {
if (element && event && handler) {
// false 表示在冒泡阶段执行
// true 表示在捕获阶段执行
element.addEventListener(event, handler, false);
}
};
} else {
// IE 中使用 attachEvent 添加事件监听
return function(element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
};
}
})();
этоon
Метод используется для привязки событий к заданному элементу.При внимательном рассмотрении исходного кода обнаруживается, что он использует функцию немедленного выполнения (МИЭФ), а затем экспортирует результат выполнения.Результатом его выполнения по-прежнему является функция . Здесь есть два вопроса:
- Зачем использовать немедленную функцию?
- Зачем возвращать функцию?
Давайте поговорим о втором, возврат функции, очевидно, использует "Закрытие", преимущество закрытия заключается в том, что "доступ к внешней области', например здесьisServer
то естьdom.js
определенные в нем переменные. Но использование замыканий приводит к "утечка памяти", если не уничтожить, наша память будет перегружена, поэтому здесь мы используем"выполнить функцию немедленно" для устранения побочных эффектов замыканий,
bar.js/render
возвращайся сноваBar
компонент, который до сих пор используетсяrender
функция для рендеринга компонента:
render(h) {
const { size, move, bar } = this;
return (
<div
class={ ['el-scrollbar__bar', 'is-' + bar.key] }
onMousedown={ this.clickTrackHandler } >
<div
ref="thumb"
class="el-scrollbar__thumb"
onMousedown={ this.clickThumbHandler }
style={ renderThumbStyle({ size, move, bar }) }>
</div>
</div>
);
},
Визуализированную структуру можно увидеть на предыдущем изображении, которое представляет собой два вложенных друг в другаdiv
, дваdiv
все связаныonmousedown
События, используемые для обработки событий нажатия мыши, вstyle
еще одинrenderThumbStyle
функция, давайте сначала посмотрим на функцию этой функции:
export function renderThumbStyle({ move, size, bar }) {
const style = {};
// 平移多少距离
const translate = `translate${bar.axis}(${ move }%)`;
// 设置滚动条的宽/高
style[bar.size] = size;
style.transform = translate;
style.msTransform = translate;
style.webkitTransform = translate;
return style;
};
Всякий раз, когда список прокручивается, полоса прокрутки также будет меняться, ее движение контролируется этой функцией, посмотрите на прокрутку до и после, ееstyle
Изменение:
translateY
изменился, то есть имитирует прокрутку панорамированием, а конкретное значение имеет родительский компонент (здесьel-scrollbar
) Прошло более.
bar.js/methods
Далее рассмотрим в нем несколько методов, все они связаны с привязкой событий:
// 鼠标按钮在 滚动条上 被按下时的事件处理方法
clickThumbHandler(e) {
// prevent click event of right button
// ctrlKey 事件属性可返回一个布尔值,指示当事件发生时,Ctrl 键是否被按下并保持住
// e.button = 2 表示鼠标右键
if (e.ctrlKey || e.button === 2) {
return;
}
this.startDrag(e);
this[this.bar.axis]
= (e.currentTarget[this.bar.offset]
- (e[this.bar.client]
- e.currentTarget.getBoundingClientRect()[this.bar.direction]));
},
Если нажать при нажатииCtrl
Или нажмите правую кнопку мыши, чтобы остановить выполнение события напрямую, и выполните метод перетаскивания при нажатииstartDrag
// 点击并拖拽滚动条
startDrag(e) {
// 拖动的时候当前元素剩下的监听函数将不会执行
e.stopImmediatePropagation();
this.cursorDown = true;
// 给 document 绑定鼠标移动事件 和 鼠标按钮抬起事件
on(document, 'mousemove', this.mouseMoveDocumentHandler);
on(document, 'mouseup', this.mouseUpDocumentHandler);
// 禁止文字被选中
// 参考 https://www.jianshu.com/p/701cc19d2c5a
document.onselectstart = () => false;
}
объяснять
e.stopImmediatePropagation()
метод, мы обычно используем меньше. Когда к элементу привязано много событий одного типа, он будет выполнять функции обратного вызова в том порядке, в котором они связаны, но когда мы объявим этот метод в обработчике событий, остальные функции слушателя текущего элемента будут не выполнять.
// 鼠标按钮在 滚动条所在的区域 被按下时的事件处理方法
// 当鼠标点击滚动条 `上方空白处` 时,滚动条向上滚动
// 当鼠标点击滚动条 `下方空白处` 时,滚动条向下滚动
clickTrackHandler(e) {
// 获取点击的位置距离元素上边距的距离
// 即 IE 下的 offsetX/offsetY 属性
const offset
= Math.abs(e.target.getBoundingClientRect()[this.bar.direction]
- e[this.bar.client]);
// 滚动条宽/高的一半
const thumbHalf = (this.$refs.thumb[this.bar.offset] / 2);
const thumbPositionPercentage
= ((offset - thumbHalf) * 100 / this.$el[this.bar.offset]);
// 举个例子
// wrap.scrollTop = -10(假数据) * wrap.scrollHeight / 100
this.wrap[this.bar.scroll]
= (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100);
}
Этот метод используется для обработки события, когда щелкают внешний слой полосы прокрутки, и реализует эффект прокрутки, щелкнув пустое место.startDrag
дляmousemove
а такжеmouseup
Метод расчета мониторинга событий подобен вышеописанному, поэтому здесь он не приводится для экономии места.
Посмотрев на привязку событий мыши, следует обратить внимание на то, что должен быть мониторинг отмены событий, особенно событий при движении мыши, что используется в исходном коде.
off
метод, специфический иon
аналогичный.
продолжать решать нашиmain.js/render
яма вырыта внутриscrollbarWidth
а такжеtoObject
scrollbar-width.js
Этот файл очень простой, он для расчета ширины полосы прокрутки, которая идет в комплекте с системой, я посмотрел, и этот метод в основном такой же, как и в Интернете.
export default function() {
if (Vue.prototype.$isServer) return 0;
// 如果存在 scrollBarWidth 就直接返回
if (scrollBarWidth !== undefined) return scrollBarWidth;
const outer = document.createElement('div');
outer.className = 'el-scrollbar__wrap';
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.position = 'absolute';
outer.style.top = '-9999px';
document.body.appendChild(outer);
// 没有滚动条时的宽度 = 元素的 offsetWidth
const widthNoScroll = outer.offsetWidth;
// 使外层可滚动并且出现滚动条
outer.style.overflow = 'scroll';
const inner = document.createElement('div');
// 设置 width 为 100% 时,强制子元素的内容宽度等于父元素内容宽度
// 当子元素内容宽度大于父元素的内容宽度时,就会出现滚动条
inner.style.width = '100%';
outer.appendChild(inner);
const widthWithScroll = inner.offsetWidth;
outer.parentNode.removeChild(outer);
scrollBarWidth = widthNoScroll - widthWithScroll;
return scrollBarWidth;
};
Но здесь я думаю, что он использует неправильный атрибут при расчете,inner
не следует использоватьoffsetWidth
вместо этого вы должны использоватьclientWidth
,потому чтоoffsetWidth
Он включает в себя полосу прокрутки, поэтому его вообще нельзя вычислить.Я не знаю, то ли они написали это неправильно, то ли я неправильно понял.В любом случае, окончательный результат этого метода равен 0, потому что я запускал его в Google. Chrome для Mac. Еще раз, вы не можете получить ширину полосы прокрутки, установите ееoverflow
Нет способа сохранить полосу прокрутки, я не знаюWindows
Что происходит в системе. Пожалуйста, запустите этот метод еще раз и сообщите мне в комментариях, спасибо.
util.js/toObject
function extend(to, _from) {
// _from 如果是基本数据类型就不会循环
for (let key in _from) {
to[key] = _from[key];
}
return to;
}
// 把数组里面的所有对象转成一个对象
export function toObject(arr) {
var res = {};
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
Метод здесь очень простой, который заключается в переносе свойств всех объектов в массиве в новый объект путем обхода.Если в массиве есть базовый тип данных, он будет пропущен напрямую.
Здесь нашscrollbar
Весь анализ пройден, но еще не время, когда цветы готовы, и есть еще кое-что.el-option
компоненты.
el-option
el-option
раздел содержит сам компонент иel-option-group
компоненты,option
Это компонент, который фактически отображает раскрывающийся список, и его отображение на странице<li>
этикетка, этоoption
В структуре шаблона есть слот по умолчанию для отображения текстового содержимого элемента списка. из-заoption
Многоselect
Метод компонента связан, поэтому я планирую разобрать его в следующей статье, сначала рассмотрим несколько простых:
// 判断两个参数是否相等
isEqual(a, b) {
if (!this.isObject) {
return a === b;
} else {
// 拿到 select 组件实例的 valueKey
// valueKey 是作为 value 唯一标识的键名,绑定值为对象类型时必填
const valueKey = this.select.valueKey;
return getValueByPath(a, valueKey) === getValueByPath(b, valueKey);
}
}
getValueByPath
даutil
Импортированный внутрь, этот метод в основном используется для доступа к свойствам, указанным объектом:
/**
* 深层次访问对象的属性
* @param {Object} object 目标对象
* @param {string} prop 属性名 xxx.xxx.xxx 形式
*/
export const getValueByPath = function(object, prop) {
prop = prop || '';
// paths => [xxx, xxx, xxx]
// object: {
// xxx: {
// xxx: {
// xxx: 'xxx'
// }
// }
// }
const paths = prop.split('.');
// 把对象保存起来,以免改变了原有对象
let current = object;
let result = null;
for (let i = 0, j = paths.length; i < j; i++) {
const path = paths[i];
if (!current) break;
// 当到达指定的属性名时,返回它的属性值
if (i === j - 1) {
result = current[path];
break;
}
// 否则继续往下遍历
current = current[path];
}
return result;
};
Но на мой взгляд, официальная реализация может быть проще, потому что, поскольку имя атрибута сохраняется в массиве, не лучше ли использовать метод массива, а затем использоватьwhile
Этого можно добиться, зациклив несколько строк кода:
function getValByPath(obj, path) {
const paths = path.split('.')
let res = obj
let prop
while ((prop = paths.shift())) {
res = res[prop]
}
return res
}
Посмотрите на другой метод:
// 鼠标移动时触发的事件监听方法
hoverItem() {
// 如果当前项没有被禁用,就设置 select 组件的 `hoverIndex`
// 它的值为当前列表项在 options 数组里的索引
if (!this.disabled && !this.groupDisabled) {
this.select.hoverIndex = this.select.options.indexOf(this);
}
}
В основном отображается, когда мышь перемещается по элементу спискаhover
состояние, конкретная реализация помещается вselect
в. Остальные здесь нужно будет проанализировать позже, я действительно не двигаюсь... Что касаетсяoption-group
Содержание внутри простое, иoption
Разница не большая, просто взгляните на нее, и я не буду ее здесь писать.
Резюме и размышления
Пока что мы наконецselect
Анализируется часть шаблона компонента, обратите внимание, что это часть шаблона, настоящая большая голова не приходит, вselect
Большинство методов в нем занимают около 400 строк, остальные — это какие-то атрибуты и хуки жизненного цикла, о методах я расскажу в следующей статье.select
шаблон:
- Во-первых, весь
select
Компонент состоит из поля ввода и раскрывающегося списка. - Поле ввода использует
el-input
компонент, раскрывающийся список используетel-select-menu
компоненты -
el-select-menu
добавляется к узлу body черезv-show
Переключить отображение и скрытие - Раскрывающийся список содержит встроенный компонент прокрутки.
el-scrollbar
- Использование пользовательской полосы прокрутки в компоненте прокрутки
Bar
компоненты - элементы списка
el-option
а такжеel-option-group
оказанныйul
этикетки иli
Этикетка
В этой статье все еще есть нерешенные вопросы:
-
el-tag
Компоненты не анализируются подробно - анимация
transition
Компонент не анализировался
В заключение я вижуselect
Ощущение компонентов, у меня ушла неделя на то, чтобы прочитать исходный код и написать эту статью, и я прочитал только небольшую часть.Я должен сказать, что здесь задействовано слишком много знаний.Для такого фронтенда, как я. Сяобай, это действительно слишком сложно. На этой неделе часто бывают моменты, когда я больше не могу его смотреть. Есть некоторые точки знаний, которых я никогда раньше не видел. Постоянно читая документы и блоги, я постепенно вошел в это состояние. Вы берете часть кода и запускаете его в браузере, и вы можете сразу понять принцип, нажав точку останова (я действительно не знаю, как запустить весь проект, и я пробовал много методов без успеха ). В течение этого периода я также просмотрел множество учебных пособий и API-интерфейсов Vue, и я постепенно обновлял свое понимание Vue. Я верю, что стану более опытным в использовании Vue в будущей разработке, потому что понимание концепций реальных проектов , и постепенно, когда вы накопите достаточно, вы сможете сформировать полный замкнутый цикл знаний. При просмотре исходного кода "Задайте еще несколько причин, действительно помогает вам понять это. Другой - идея дизайна компонентов. Это очень абстрактная вещь. Вы не можете понять, просто взглянув на один или два компонента. Вам нужно прочитать много исходного кода компонента и знать, какие проблемы он решает и какие функции, которые у него есть.Почему вы хотите проектировать таким образом?Когда вы смотрите на компонент, вы можете быстро понять эти три вопроса, тогда у вас будет представление о компоненте. Этого можно достичь только в том случае, если вам нужно много читать и практиковаться, вы не можете достичь этого, прочитав несколько блогов и взглянув на два компонента.
Что ж, ждите следующей статьи. Если вам понравилась эта статья, вы можете поставить лайк, чтобы ее увидело больше людей. Если что-то не так с анализом в статье, пожалуйста, укажите на это. Вы также можете добавить мой WeChat [Liu472362746] Обсудите вместе, и я отправлю подробный код наGithubсклад.
портал
【2020.3.15】Elementui Ultra-подробный анализ исходного кода - ввод
[2020.3.16]Сверхдетальный анализ исходного кода ElementUI — Layout
【2020.3.18】Сверхдетальный анализ исходного кода ElementUI - Радио