предисловие
В этой статьевысокая частотаВопросы, связанные с интервью, связанные с Vue, которые появляются и приходят сПодробный ответСложность делится на три типа: легкий, средний и сложный.Вы можете проверить свой уровень Vue, не читая ответ.Если вам интересен принцип, пожалуйста, проверьте редакторСерия рукописных исходных кодов VueЕсли у вас есть разные мнения по поводу ответа, добро пожаловать в область комментариев для дополнительных обсуждений. Наконец, вы можете нажатьСвязьПрисоединяйтесь к группе разработчиков Brother Shark, вступайте внутрь, обсуждайте технологии, ловите рыбу, просите о помощи (войдите в группу, чтобы бесплатно получить интеллект-карту исходного кода Vue2)
Это непросто организовать. Если эта статья окажется вам полезной, помнитеКак СанлианБольшое спасибо!
Простой
1 Разница между MVC и MVVM
MVC
Полное название MVC — Model View Controller, что является аббревиатурой от model-view-controller, парадигмы разработки программного обеспечения.
- Модель: часть приложения, которая обрабатывает логику данных приложения. Обычно объекты модели отвечают за доступ к данным в базе данных.
- View (представление): это часть приложения, которая обрабатывает отображение данных. Обычно представления создаются из данных модели.
- Контроллер (Controller): это часть приложения, которая обрабатывает взаимодействие с пользователем. Обычно контроллер отвечает за чтение данных из представления, управление пользовательским вводом и отправку данных в модель.
Идея MVC: описание одного предложения заключается в том, что контроллер отвечает за отображение данных модели в представлении, другими словами, за назначение данных модели представлению в контроллере.
MVVM
MVVM добавляет новый класс VM
- Уровень ViewModel: он выполняет две функции для двусторонней привязки данных: первая — преобразовать [модель] в [представление], то есть преобразовать данные, переданные серверной частью, в страницу, которую вы видите. Способ достижения: привязка данных. Второй — преобразовать [представление] в [модель], то есть преобразовать страницу, которую вы видите, во внутренние данные. Способ добиться этого: прослушивание событий DOM.
Самая большая разница между MVVM и MVC заключается в том, что он реализует автоматическую синхронизацию между View и Model, то есть при изменении свойств Model нам больше не нужно вручную манипулировать элементами Dom для изменения отображения View, но после изменения свойств, свойства, соответствующие отображению слоя просмотра, автоматически изменятся (в соответствии с идеей Vue, основанной на данных)
В целом MVVM намного проще, чем MVC, что не только упрощает бизнес и зависимости интерфейса, но и решает проблему частого обновления данных, избавляя от необходимости использовать селекторы для манипулирования элементами DOM. Поскольку в MVVM представление не знает о существовании модели, а модель и модель представления не могут наблюдать за представлением, этот шаблон низкой связи улучшает возможность повторного использования кода.
Примечание. Vue не полностью соответствует идее MVVM. Это также объясняется на самом официальном сайте.
Итак, вопрос в том, почему чиновник говорит, что Vue не полностью следует идее MVVM?
- Строгий MVVM требует, чтобы View не мог напрямую взаимодействовать с Model, а Vue предоставляет свойство $refs, которое позволяет Model напрямую управлять View, что нарушает это правило, поэтому Vue не полностью следует MVVM.
2 Почему данные — это функция
Данные в компоненте записываются как функция, а данные определяются в виде возвращаемого функцией значения, так что каждый раз при повторном использовании компонента будут возвращаться новые данные, аналогично созданию частного пространства данных для каждого экземпляр компонента, что позволяет каждому экземпляру компонента поддерживать свои собственные данные. И просто запись его в виде объекта заставляет все экземпляры компонентов совместно использовать часть данных, что приведет к изменению, которое изменит все.
3 Каковы способы взаимодействия компонентов Vue
-
родительские компоненты props и $emit передают данные дочерним компонентам через реквизиты, а дочерние компоненты передают данные родительским компонентам через события запуска $emit
-
$parent,$children Получить родительский компонент текущего компонента и дочерние компоненты текущего компонента
-
$attrs и $listeners A->B->C. Vue 2.4 предоставляет $attrs и $listeners для решения этой проблемы.
-
Переменные предоставляются путем предоставления в родительском компоненте, а затем внедряются в дочерний компонент посредством инъекции. (Официально не рекомендуется для использования в реальном бизнесе, но обычно используется при написании библиотек компонентов)
-
$refs получить экземпляр компонента
-
Шина событий случая сборки EventBus Brothers для передачи данных может использоваться таким образом,
-
vuex управление состоянием
4 Каковы методы жизненного цикла Vue?На каком этапе обычно отправляется запрос?
beforeCreateПосле инициализации экземпляра перед вызовом вызывается наблюдатель данных и конфигурация события/наблюдателя. Данные и методы для данных, методов, вычислений и часов недоступны на текущем этапе.
createdВызывается после создания экземпляра. На этом этапе экземпляр завершил следующую настройку: наблюдатель данных, работа со свойствами и методами и обратный вызов событий наблюдения/события. Здесь нет $el.Если вам нужно взаимодействовать с Домом, вы можете получить доступ к Дому через vm.$nextTick
beforeMountВызывается до начала монтирования: связанная функция рендеринга вызывается в первый раз.
mountedПроисходит после завершения монтирования, на данном этапе монтируется настоящий Дом, происходит привязка данных в обе стороны, возможен доступ к узлу Дом
beforeUpdateВызывается при обновлении данных перед повторным рендерингом и исправлением виртуального DOM. Дальнейшие изменения состояния могут быть сделаны в этом хуке без запуска дополнительного процесса повторного рендеринга.
updatedПроисходит после завершения обновления, компонент текущей фазы Дом завершил обновление. Предостережение заключается в том, чтобы избежать изменения данных в течение этого времени, так как это может привести к бесконечному циклу обновлений, этот хук не вызывается во время рендеринга на стороне сервера.
beforeDestroyВызывается перед уничтожением экземпляра. На этом этапе экземпляр все еще полностью доступен. На этом этапе мы можем сделать последние штрихи, например, сбросить таймер.
destroyedВызывается после уничтожения экземпляра Vue. После вызова все, на что указывает экземпляр Vue, будет развязано, все прослушиватели событий будут удалены, а все дочерние экземпляры уничтожены. Этот хук не вызывается во время рендеринга на стороне сервера.
activatedэксклюзивный keep-alive, вызывается при активации компонента
deactivatedэксклюзивный keep-alive, вызывается при уничтожении компонента
На каком шаге инициируется асинхронный запрос?
Асинхронные запросы могут выполняться в функциях ловушек created, beforeMount и mount, потому что в этих трех функциях ловушек данные были созданы, и данные, возвращаемые сервером, могут быть назначены.
Если асинхронный запрос не должен полагаться на Dom, рекомендуется вызывать асинхронный запрос в созданной функции ловушки, потому что вызов асинхронного запроса в созданной функции ловушки имеет следующие преимущества:
- Он может быстрее получать данные на стороне сервера и сокращать время загрузки страницы;
- ssr не поддерживает функции beforeMount и монтируемые хуки, поэтому добавление его в created способствует согласованности;
5 Разница между v-if и v-show
v-if будет преобразован в троичное выражение в процессе компиляции, и узел не будет отображаться, если условие не выполнено.
v-show будет скомпилирован в инструкцию, а стиль управления скроет соответствующий узел, когда условие не будет выполнено (display:none)
сцены, которые будут использоваться
v-if подходит для сценариев, в которых условия редко меняются во время выполнения и нет необходимости часто переключаться.
v-show подходит для сценариев, требующих очень частых условий переключения
Добавлено расширение: разница между отображением: нет, видимостью: скрыто и непрозрачностью: 0?
6 Расскажите о встроенных инструкциях vue
7 Как понять односторонний поток данных Vue
Данные всегда передаются от родительского компонента к дочернему компоненту.Дочерний компонент не имеет права изменять данные, переданные от родительского компонента, а может только запрашивать у родительского компонента изменение исходных данных. Это предотвращает случайные изменения родительского состояния из дочерних компонентов, которые могут сделать поток данных вашего приложения непонятным.
Примечание: В дочернем компоненте используйте v-model напрямую для привязки реквизита, переданного от родительского компонента.Это неправильный способ написания.Среда разработки сообщит о предупреждении.
Если вы действительно хотите изменить значение реквизита родительского компонента, вы можете определить переменную в данных и инициализировать ее значением реквизита, а затем использовать $emit, чтобы уведомить родительский компонент об изменении
8 Разница между вычисляемым и наблюдаемым и сценариями применения
Computed — это вычисляемое свойство, которое использует другие свойства для вычисления значений, а вычисленное значение кэшируется. Только когда вычисляемое значение изменяется, оно возвращает содержимое. Оно может устанавливать геттеры и сеттеры.
Когда часы прослушивают изменение значения, они выполняют обратный вызов, и в обратном вызове могут выполняться некоторые логические операции.
Вычисляемые свойства обычно используются при рендеринге шаблонов. Значение вычисляется, полагаясь на другие реагирующие объекты или даже вычисляемые свойства, в то время как свойства прослушивания подходят для наблюдения за изменениями в определенном значении для выполнения сложной бизнес-логики.
Подробное объяснение принципа вычисленных свойствпортал
Подробное объяснение принципа слуховых свойствпортал
9 Почему не рекомендуется использовать v-if и v-for вместе
Не используйте v-for и v-if в одном и том же теге, потому что сначала анализируется v-for, а затем v-if. Если вам нужно использовать его одновременно, вы можете записать его как вычисляемое свойство.
Средняя
10 принципов отзывчивых данных Vue2.0
Общая идея — захват данных + режим наблюдателя.
Внутри объекта метод defineReactive используется для захвата свойств с помощью Object.defineProperty (захватываются только существующие свойства), а массив реализуется путем переопределения метода массива. Когда страница использует соответствующий атрибут, каждый атрибут имеет свой собственный атрибут dep, в котором хранится наблюдатель, от которого он зависит (коллекция зависимостей).При изменении атрибута он уведомляет соответствующий наблюдатель об обновлении (распространении обновления).
Соответствующий код выглядит следующим образом
class Observer {
// 观测值
constructor(value) {
this.walk(value);
}
walk(data) {
// 对象上的所有属性依次进行观测
let keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let value = data[key];
defineReactive(data, key, value);
}
}
}
// Object.defineProperty数据劫持核心 兼容性在ie9以及以上
function defineReactive(data, key, value) {
observe(value); // 递归关键
// --如果value还是一个对象会继续走一遍odefineReactive 层层遍历一直到value不是对象才停止
// 思考?如果Vue数据嵌套层级过深 >>性能会受影响
Object.defineProperty(data, key, {
get() {
console.log("获取值");
//需要做依赖收集过程 这里代码没写出来
return value;
},
set(newValue) {
if (newValue === value) return;
console.log("设置值");
//需要做派发更新过程 这里代码没写出来
value = newValue;
},
});
}
export function observe(value) {
// 如果传过来的是对象或者数组 进行属性劫持
if (
Object.prototype.toString.call(value) === "[object Object]" ||
Array.isArray(value)
) {
return new Observer(value);
}
}
Подробное объяснение принципа адаптивных данныхпортал
11 Как Vue обнаруживает изменения массива
Из соображений производительности массив не использует defineProperty для перехвата каждого элемента массива, а выбирает переписывание 7 методов массива (push, shift, pop, splice, unshift, sort, reverse) (идея нарезки АОП)
Таким образом, изменение индекса и длины массива в Vue не может быть отслежено. Необходимо изменить массив с помощью вышеуказанных 7 методов мутации, чтобы вызвать обновление наблюдателя, соответствующего массиву.
Соответствующий код выглядит следующим образом
// src/obserber/array.js
// 先保留数组原型
const arrayProto = Array.prototype;
// 然后将arrayMethods继承自数组原型
// 这里是面向切片编程思想(AOP)--不破坏封装的前提下,动态的扩展功能
export const arrayMethods = Object.create(arrayProto);
let methodsToPatch = [
"push",
"pop",
"shift",
"unshift",
"splice",
"reverse",
"sort",
];
methodsToPatch.forEach((method) => {
arrayMethods[method] = function (...args) {
// 这里保留原型方法的执行结果
const result = arrayProto[method].apply(this, args);
// 这句话是关键
// this代表的就是数据本身 比如数据是{a:[1,2,3]} 那么我们使用a.push(4) this就是a ob就是a.__ob__ 这个属性就是上段代码增加的 代表的是该数据已经被响应式观察过了指向Observer实例
const ob = this.__ob__;
// 这里的标志就是代表数组有新增操作
let inserted;
switch (method) {
case "push":
case "unshift":
inserted = args;
break;
case "splice":
inserted = args.slice(2);
default:
break;
}
// 如果有新增的元素 inserted是一个数组 调用Observer实例的observeArray对数组每一项进行观测
if (inserted) ob.observeArray(inserted);
// 之后咱们还可以在这里检测到数组改变了之后从而触发视图更新的操作--后续源码会揭晓
return result;
};
});
Подробное объяснение принципа наблюдения массивовпортал
12 Использовали ли вы vue3.0 и насколько хорошо знаете?
-
Изменения в принципе отзывчивости Vue3.x использует прокси для замены Object.defineProperty версии Vue2.x
-
Как объявить параметры компонента Vue3.x использует Composition API setup — это новая опция в Vue3.x, которая является отправной точкой для использования Composition API в компонентах.
-
Изменения синтаксиса шаблона синтаксис именованного слота пользовательская директива обновление v-модели
-
Другие изменения саспенс Поддержка компонентов Fragment (несколько корневых узлов) и Portal (рендеринг содержимого компонентов в других частях dom) и работа с некоторыми особыми сценариями. На основе оптимизации treeshaking предоставляется больше встроенных функций.
Новые функции Vue3.0 и сводка опыта использованияпортал
13 Разница между адаптивным принципом Vue 3.0 и 2.0
Vue3.x использует прокси вместо Object.defineProperty. Потому что Proxy может напрямую следить за изменениями объектов и массивов, а способов перехвата целых 13.
Соответствующий код выглядит следующим образом
import { mutableHandlers } from "./baseHandlers"; // 代理相关逻辑
import { isObject } from "./util"; // 工具方法
export function reactive(target) {
// 根据不同参数创建不同响应式对象
return createReactiveObject(target, mutableHandlers);
}
function createReactiveObject(target, baseHandler) {
if (!isObject(target)) {
return target;
}
const observed = new Proxy(target, baseHandler);
return observed;
}
const get = createGetter();
const set = createSetter();
function createGetter() {
return function get(target, key, receiver) {
// 对获取的值进行放射
const res = Reflect.get(target, key, receiver);
console.log("属性获取", key);
if (isObject(res)) {
// 如果获取的值是对象类型,则返回当前对象的代理对象
return reactive(res);
}
return res;
};
}
function createSetter() {
return function set(target, key, value, receiver) {
const oldValue = target[key];
const hadKey = hasOwn(target, key);
const result = Reflect.set(target, key, value, receiver);
if (!hadKey) {
console.log("属性新增", key, value);
} else if (hasChanged(value, oldValue)) {
console.log("属性值被修改", key, value);
}
return result;
};
}
export const mutableHandlers = {
get, // 当获取属性时调用此方法
set, // 当修改属性时调用此方法
};
14 Порядок выполнения функции привязки жизненного цикла родительско-дочернего компонента Vue
- Загрузить процесс рендеринга
родитель beforeCreate->родитель создан->родитель beforeMount->дочерний элемент beforeCreate->дочерний элемент создан->дочерний элемент beforeMount->дочерний элемент смонтирован->родительский элемент
- Процесс обновления подкомпонента
родитель до обновления-> дочерний перед обновлением-> дочерний обновлен-> родительский обновлен
- Процесс обновления родительского компонента
родитель перед обновлением-> родитель обновлен
- процесс разрушения
родитель перед уничтожением-> дочерний перед уничтожением-> дочерний элемент уничтожен-> родитель уничтожен
15 Что такое виртуальный DOM и каковы его плюсы и минусы
Так как манипулировать DOM в браузере дорого. Частые манипуляции с DOM вызовут определенные проблемы с производительностью. Вот почему рождается виртуальный Дом. Виртуальный DOM Vue2 заимствует реализацию библиотеки с открытым исходным кодом snabbdom. Суть Virtual DOM заключается в описании узла DOM с помощью собственного JS-объекта, который является абстракцией реального DOM.
преимущество:
-
Гарантированный нижний предел производительности: виртуальный DOM фреймворка должен адаптироваться к любым операциям, которые могут быть сгенерированы API верхнего уровня. Реализация некоторых операций DOM должна быть универсальной, поэтому его производительность не оптимальна, но по сравнению с грубой Производительность операции DOM намного лучше, поэтому виртуальный DOM фреймворка может как минимум гарантировать, что вы все еще можете обеспечить хорошую производительность без ручной оптимизации, то есть нижний предел гарантированной производительности;
-
Нет необходимости вручную манипулировать DOM: нам больше не нужно вручную манипулировать DOM, нам нужно только написать логику кода View-Model.Фреймворк свяжет виртуальный DOM и данные в обоих направлениях, чтобы помочь нам обновить представление предсказуемым образом, значительно повышая эффективность нашей разработки;
-
Кроссплатформенность: виртуальный DOM по сути является объектом JavaScript, а DOM тесно связан с платформой.В отличие от этого, виртуальный DOM может выполнять более удобные кроссплатформенные операции, такие как серверный рендеринг, разработка weex и т. д.
недостаток:
-
Невозможно выполнить экстремальную оптимизацию: хотя виртуальный DOM + разумная оптимизация достаточны для удовлетворения требований к производительности большинства приложений, в некоторых приложениях с чрезвычайно высокими требованиями к производительности виртуальный DOM не может быть выбран и оптимизирован.
-
При первом рендеринге большого количества DOM это будет медленнее, чем вставка innerHTML из-за дополнительного уровня вычисления виртуального DOM.
16 v-образный принцип
v-модель - это просто синтаксический сахар
v-model внутренне использует разные свойства и выдает разные события для разных элементов ввода:
- элементы text и textarea используют свойство value и событие ввода;
- флажок и радио используют проверенное свойство и событие изменения;
- Поле выбора имеет значение как реквизит и изменение как событие.
Примечание. Для языков, требующих методов ввода (таких как китайский, японский, корейский и т. д.), вы обнаружите, что V-модель не будет обновляться во время ввода текста комбинации методов ввода.
на обычных этикетках
<input v-model="sth" /> //这一行等于下一行
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
на компоненте
<currency-input v-model="price"></currentcy-input>
<!--上行代码是下行的语法糖
<currency-input :value="price" @input="price = arguments[0]"></currency-input>
-->
<!-- 子组件定义 -->
Vue.component('currency-input', {
template: `
<span>
<input
ref="input"
:value="value"
@input="$emit('input', $event.target.value)"
>
</span>
`,
props: ['value'],
})
17 Почему v-for добавляет ключ
Без использования ключей Vue использует алгоритм, который сводит к минимуму динамические элементы и пытается изменить/повторно использовать элементы одного и того же типа на месте, насколько это возможно. Ключ — это единственная метка для vnode в Vue. Благодаря этому ключу наша операция сравнения может быть более точной и быстрой.
точнее: поскольку ключ не используется повторно на месте, в функции того же узла a.key === сравнение b.key позволяет избежать повторного использования на месте. Так будет точнее.
Быстрее: Используйте уникальность ключа для создания объекта карты для получения соответствующего узла, что быстрее, чем метод обхода.
Соответствующий код выглядит следующим образом
// 判断两个vnode的标签和key是否相同 如果相同 就可以认为是同一节点就地复用
function isSameVnode(oldVnode, newVnode) {
return oldVnode.tag === newVnode.tag && oldVnode.key === newVnode.key;
}
// 根据key来创建老的儿子的index映射表 类似 {'a':0,'b':1} 代表key为'a'的节点在第一个位置 key为'b'的节点在第二个位置
function makeIndexByKey(children) {
let map = {};
children.forEach((item, index) => {
map[item.key] = index;
});
return map;
}
// 生成的映射表
let map = makeIndexByKey(oldCh);
Подробное объяснение алгоритма сравненияпортал
18 Принцип привязки событий Vue
Собственная привязка событий привязывается к реальным элементам через addEventListener, а привязка событий компонента реализуется через пользовательскую переменную Vue $on. Если вы хотите использовать нативные события в компоненте, вам нужно добавить модификатор .native, который эквивалентен обработке дочернего компонента как обычного HTML-тега в родительском компоненте, а затем добавить собственное событие.
$on и $emit основаны на модели публикации-подписки, поддерживая центр событий.Когда он включен, события сохраняются в центре событий по имени, называемому подписчиками, а затем emit публикует соответствующие события и выполняет события в событии. центр. соответствующий слушатель
Рукописный принцип публикации и подпискипортал
19 Что такое функция хука маршрутизации vue-router и каков порядок выполнения
Процесс выполнения хука маршрутизации, типы функций хука: глобальная защита, защита маршрутизации, защита компонентов.
Полный процесс анализа навигации:
- Навигация запущена.
- Вызовите охрану beforeRouteLeave для деактивированного компонента.
- Вызов глобального охранника перед каждым.
- Вызовите защиту beforeRouteUpdate (2.2+) в повторно используемом компоненте.
- Вызовите beforeEnter в конфигурации маршрутизации.
- Разобрать компоненты асинхронной маршрутизации.
- Вызовите beforeRouteEnter для активированного компонента.
- Вызвать глобальную защиту beforeResolve (2.5+).
- Навигация подтверждена.
- Вызовите глобальный хук afterEach.
- Запустить обновление DOM.
- Вызовите функцию обратного вызова, переданную next в стороже beforeRouteEnter, и созданный экземпляр компонента будет передан в качестве параметра функции обратного вызова.
20 Что такое динамическая маршрутизация vue-router и в чем проблема
Нам часто нужно сопоставить все маршруты, соответствующие определенному шаблону, с одним и тем же компонентом. Например, у нас есть компонент User, который используется для отображения всех пользователей с разными идентификаторами. Затем мы можем использовать «динамический сегмент» в пути маршрутизации vue-router для достижения этого эффекта:
const User = {
template: "<div>User</div>",
};
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: "/user/:id", component: User },
],
});
Вопрос: Что делать, если параметры маршрутизации недействительны из-за повторного использования компонентов vue-router?
Решение:
1. Прослушиваем параметры маршрутизации через watch и снова отправляем запрос
watch: { //通过watch来监听路由变化
"$route": function(){
this.getData(this.$route.params.xxx);
}
}
2. Используйте :key, чтобы предотвратить «повторное использование»
<router-view :key="$route.fullPath" />
21 Расскажите о моем личном понимании vuex
Vuex — это глобальная система управления состоянием, специально предназначенная для Vue, которая используется для обмена данными, кэширования данных и т. д. в нескольких компонентах. (Невозможно сохранить, внутренний основной принцип заключается в создании глобального экземпляра нового Vue)
В основном он включает в себя следующие модули:
- Состояние: здесь можно установить структуру данных, определяющую состояние приложения, и начальное состояние по умолчанию.
- Геттеры: позволяет компонентам получать данные из хранилища, вспомогательная функция mapGetters просто сопоставляет геттеры в хранилище с локальными вычисляемыми свойствами.
- Мутация: единственный способ изменить состояние в хранилище и должна быть синхронной функцией.
- Действие: используется для отправки мутаций вместо прямого изменения состояния и может содержать произвольные асинхронные операции.
- Модуль: позволяет разделить одно хранилище на несколько хранилищ и хранить их в одном дереве состояний одновременно.
22 Как решить проблему потери данных при обновлении страницы Vuex
Необходимо обеспечить сохранение данных vuex, обычно используйте локальную схему хранения для сохранения данных, вы можете разработать собственную схему хранения или использовать сторонние плагины.
Рекомендуется использовать плагин vuex-persist, который является плагином для постоянного хранилища Vuex. Вам не нужно вручную обращаться к хранилищу, а сохранять состояние непосредственно в файл cookie или localStorage.
23 Почему Vuex разделяет модули и добавляет пространства имен
модуль: Благодаря использованию единого дерева состояний все состояния приложения будут сосредоточены в относительно большом объекте. Когда приложение становится очень сложным, объект хранилища может сильно раздуться. Чтобы решить вышеуказанные проблемы, Vuex позволяет нам разделить хранилище на модули. Каждый модуль имеет свое состояние, мутации, действия, геттеры и даже вложенные подмодули.
Пространства имен: По умолчанию действия, мутации и геттеры внутри модулей регистрируются в глобальном пространстве имен — это позволяет нескольким модулям реагировать на одну и ту же мутацию или действие. Если вы хотите, чтобы ваш модуль был более инкапсулированным и пригодным для повторного использования, вы можете сделать его модулем с пространством имен, добавив namespaced: true . Когда модуль регистрируется, все его геттеры, действия и мутации автоматически именуются в соответствии с путем, зарегистрированным модулем.
24 Когда-нибудь использовали Vue SSR? Разговор о ССР
SSR — это рендеринг на стороне сервера, то есть работа по рендерингу тегов Vue в HTML на стороне клиента завершается на стороне сервера, а затем HTML возвращается непосредственно клиенту.
преимущество:
SSR имеет лучше SEO и загружать быстрее выше сгиба
недостаток:Условия разработки будут ограничены. Рендеринг на стороне сервера поддерживает только два хука beforeCreate и created. Когда нам нужны некоторые внешние библиотеки расширений, требуется специальная обработка. Приложение для рендеринга на стороне сервера также должно находиться в среде выполнения Node.js.
Сервер будет иметь большую потребность в нагрузке
25 Какие шаблоны проектирования используются в vue
1. Фабричный шаблон — создайте экземпляр, передав параметры
Виртуальный DOM возвращает Vnode базовой метки и Vnode компонента в соответствии с различными параметрами.
2. Паттерн Singleton — вся программа имеет один и только один экземпляр
Метод регистрации плагина устанавливает vuex и vue-router, если в системе есть экземпляр, он вернется напрямую.
3. Режим публикации-подписки (механизм событий vue)
4. Шаблон наблюдателя (принцип реактивных данных)
5. Режим оформления: (использование декоратора @)
6. Паттерн стратегии Паттерн стратегии означает, что объект имеет определенное поведение, но в разных сценариях поведение имеет разные схемы реализации — например, стратегия слияния вариантов
... другие режимы приветствуются
26 Какую оптимизацию производительности Vue вы сделали?
Здесь указана только оптимизация производительности для Vue. Оптимизация производительности всего проекта — это большой проект. Вы можете написать еще одну статью об оптимизации производительности. Ха-ха
- Иерархия объектов не должна быть слишком глубокой, иначе производительность будет низкой.
- Не помещайте в данные данные, не требующие отклика (вы можете использовать Object.freeze() для заморозки данных)
- v-if и v-show различают сценарии использования
- Вычисляемые и наблюдаемые сценарии использования
- v-for обход должен добавить ключ, ключ предпочтительно является значением id, и избегайте одновременного использования v-if
- Оптимизация производительности списков и таблиц больших данных — виртуальный список/виртуальная таблица
- Предотвратить внутреннюю утечку, уничтожить глобальные переменные и события после уничтожения компонента
- Ленивая загрузка изображения
- Отложенная загрузка маршрута
- Внедрение сторонних плагинов по запросу
- Надлежащее использование компонентов кэша поддержки активности
- Приложение для защиты от сотрясений и дросселирования
- Рендеринг на стороне сервера SSR или предварительный рендеринг
трудность
27 сценариев и принципов использования Vue.mixin
В ежедневной разработке мы часто сталкиваемся с одинаковым или похожим кодом в разных компонентах. Функции этих кодов относительно независимы, и общую бизнес-логику можно извлечь через функцию миксина Vue. Принцип аналогичен «Наследованию объектов», когда компонент инициализируется, метод mergeOptions будет вызываться для слияния, а режим стратегии будет использоваться для слияния различных свойств. Когда компоненты и примеси имеют параметры с одинаковыми именами, эти параметры «объединяются» соответствующим образом.
Соответствующий код выглядит следующим образом
export default function initMixin(Vue){
Vue.mixin = function (mixin) {
// 合并对象
this.options=mergeOptions(this.options,mixin)
};
}
};
// src/util/index.js
// 定义生命周期
export const LIFECYCLE_HOOKS = [
"beforeCreate",
"created",
"beforeMount",
"mounted",
"beforeUpdate",
"updated",
"beforeDestroy",
"destroyed",
];
// 合并策略
const strats = {};
// mixin核心方法
export function mergeOptions(parent, child) {
const options = {};
// 遍历父亲
for (let k in parent) {
mergeFiled(k);
}
// 父亲没有 儿子有
for (let k in child) {
if (!parent.hasOwnProperty(k)) {
mergeFiled(k);
}
}
//真正合并字段方法
function mergeFiled(k) {
if (strats[k]) {
options[k] = strats[k](parent[k], child[k]);
} else {
// 默认策略
options[k] = child[k] ? child[k] : parent[k];
}
}
return options;
}
Подробное объяснение принципа работы Vue.mixinпортал
28 сценариев и принципов использования nextTick
nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。 Используйте этот метод сразу после изменения данных, чтобы получить обновленную модель DOM.主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法
Соответствующий код выглядит следующим образом
let callbacks = [];
let pending = false;
function flushCallbacks() {
pending = false; //把标志还原为false
// 依次执行回调
for (let i = 0; i < callbacks.length; i++) {
callbacks[i]();
}
}
let timerFunc; //定义异步方法 采用优雅降级
if (typeof Promise !== "undefined") {
// 如果支持promise
const p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
};
} else if (typeof MutationObserver !== "undefined") {
// MutationObserver 主要是监听dom变化 也是一个异步方法
let counter = 1;
const observer = new MutationObserver(flushCallbacks);
const textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
characterData: true,
});
timerFunc = () => {
counter = (counter + 1) % 2;
textNode.data = String(counter);
};
} else if (typeof setImmediate !== "undefined") {
// 如果前面都不支持 判断setImmediate
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
// 最后降级采用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}
export function nextTick(cb) {
// 除了渲染watcher 还有用户自己手动调用的nextTick 一起被收集到数组
callbacks.push(cb);
if (!pending) {
// 如果多次调用nextTick 只会执行一次异步 等异步队列清空之后再把标志变为false
pending = true;
timerFunc();
}
}
Подробное объяснение принципа nextTickпортал
29 сценариев и принципов использования keep-alive
keep-alive — это встроенный компонент Vue, который может реализовать кэширование компонентов и не будет удалять текущий компонент при его переключении.
-
Два часто используемых атрибута include/exclude позволяют условно кэшировать компоненты.
-
Два жизненных цикла активированы/деактивированы, чтобы знать, активен ли текущий компонент.
-
Поддерживающая активность также использует алгоритм LRU (наименее недавно использовавшийся) для выбора компонентов, которые не использовались в течение самого длительного времени, для исключения.
Соответствующий код выглядит следующим образом
export default {
name: "keep-alive",
abstract: true, //抽象组件
props: {
include: patternTypes, //要缓存的组件
exclude: patternTypes, //要排除的组件
max: [String, Number], //最大缓存数
},
created() {
this.cache = Object.create(null); //缓存对象 {a:vNode,b:vNode}
this.keys = []; //缓存组件的key集合 [a,b]
},
destroyed() {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys);
}
},
mounted() {
//动态监听include exclude
this.$watch("include", (val) => {
pruneCache(this, (name) => matches(val, name));
});
this.$watch("exclude", (val) => {
pruneCache(this, (name) => !matches(val, name));
});
},
render() {
const slot = this.$slots.default; //获取包裹的插槽默认值
const vnode: VNode = getFirstComponentChild(slot); //获取第一个子组件
const componentOptions: ?VNodeComponentOptions =
vnode && vnode.componentOptions;
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions);
const { include, exclude } = this;
// 不走缓存
if (
// not included 不包含
(include && (!name || !matches(include, name))) ||
// excluded 排除里面
(exclude && name && matches(exclude, name))
) {
//返回虚拟节点
return vnode;
}
const { cache, keys } = this;
const key: ?string =
vnode.key == null
? // same constructor may get registered as different local components
// so cid alone is not enough (#3269)
componentOptions.Ctor.cid +
(componentOptions.tag ? `::${componentOptions.tag}` : "")
: vnode.key;
if (cache[key]) {
//通过key 找到缓存 获取实例
vnode.componentInstance = cache[key].componentInstance;
// make current key freshest
remove(keys, key); //通过LRU算法把数组里面的key删掉
keys.push(key); //把它放在数组末尾
} else {
cache[key] = vnode; //没找到就换存下来
keys.push(key); //把它放在数组末尾
// prune oldest entry //如果超过最大值就把数组第0项删掉
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode);
}
}
vnode.data.keepAlive = true; //标记虚拟节点已经被缓存
}
// 返回虚拟节点
return vnode || (slot && slot[0]);
},
};
Расширенное дополнение: что такое алгоритм LRU?
Основная идея LRU заключается в том, что если к данным обращались недавно, вероятность обращения к ним в будущем также выше, поэтому мы повторно вставляем ключ компонента, попадающий в кеш, в конец this.keys, поэтому что чем дальше к голове в this.keys тем ниже вероятность обращения к данным в будущем, поэтому когда количество кэшей достигает максимального значения, мы удаляем данные с наименьшей вероятностью обращения в будущем, то есть первый кэшированный компонент в this.keys.
30 Принцип метода Vue.set
Студенты, которые понимают принцип отзывчивости Vue, знают, что изменение данных Vue не приведет к обновлению представления в двух случаях.
1. Добавьте новые свойства к экземпляру после создания экземпляра (добавьте свойства к реагирующим объектам).
2. Напрямую измените индекс массива, чтобы изменить значение массива.
Vue.set или $set работают следующим образом
Из-за реактивных данных мы добавляем атрибут __ob__ как к объекту, так и к самому массиву, представляющему экземпляр Observer. При добавлении атрибута, который не существует к объекту, новый атрибут будет оперативно отслеживаться, а затем наблюдатель, собранный dep объекта __ob__, будет запущен для обновления.Когда индекс массива изменяется, мы вызываем метод splice самого массива для обновления массива.
Соответствующий код выглядит следующим образом
export function set(target: Array | Object, key: any, val: any): any {
// 如果是数组 调用我们重写的splice方法 (这样可以更新视图)
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val;
}
// 如果是对象本身的属性,则直接添加即可
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
const ob = (target: any).__ob__;
// 如果不是响应式的也不需要将其定义成响应式属性
if (!ob) {
target[key] = val;
return val;
}
// 将属性定义成响应式的
defineReactive(ob.value, key, val);
// 通知视图更新
ob.dep.notify();
return val;
}
Подробное объяснение принципа адаптивных данныхпортал
31 Функция и принцип Vue.extend
Официальное объяснение: Vue.extend использует базовый конструктор Vue для создания «подкласса». Параметр — это объект, содержащий параметры компонента.
По сути, это конструктор подкласса.Это основная идея реализации API компонентов Vue.Идея использования прототипного наследования состоит в том, чтобы вернуть подкласс Vue и использовать mergeOptions для слияния опций входящего компонента. и параметры родительского класса.
Соответствующий код выглядит следующим образом
export default function initExtend(Vue) {
let cid = 0; //组件的唯一标识
// 创建子类继承Vue父类 便于属性扩展
Vue.extend = function (extendOptions) {
// 创建子类的构造函数 并且调用初始化方法
const Sub = function VueComponent(options) {
this._init(options); //调用Vue初始化方法
};
Sub.cid = cid++;
Sub.prototype = Object.create(this.prototype); // 子类原型指向父类
Sub.prototype.constructor = Sub; //constructor指向自己
Sub.options = mergeOptions(this.options, extendOptions); //合并自己的options和父类的options
return Sub;
};
}
Подробное объяснение принципа работы компонентов Vueпортал
32 Писали ли вы когда-нибудь инструкцию на заказ?Какой принцип?
Директивы — это, по сути, декораторы, которые являются расширениями vue для элементов HTML, добавляя пользовательские функции к элементам HTML. Когда vue компилирует DOM, он находит объект инструкции и выполняет соответствующие методы инструкции.
Существует пять жизненных циклов настраиваемых инструкций (также называемых функцией ловушки), соответственно, привязка, вставка, обновление, обновление компонента, отвязка
1. bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
2. inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
3. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
4. componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
5. unbind:只调用一次,指令与元素解绑时调用。
принцип
1. При создании синтаксического дерева ast, если встречается директива, атрибут директивы будет добавлен к текущему элементу
2. Сгенерируйте код директивы через genDirectives
3. Извлеките хук инструкции в cbs перед патчем и вызовите соответствующий хук во время процесса патча.
4. При выполнении инструкции, соответствующей функции ловушки, вызовите метод, определенный соответствующей инструкцией.
33 Что такое модификаторы Vue
модификатор события
- .stop останавливает дальнейшее распространение события
- .prevent предотвращает поведение метки по умолчанию
- .capture использует режим захвата событий, то есть здесь сначала обрабатывается событие, спровоцированное самим элементом, а затем передается на обработку внутреннему элементу
- .self запускает обработчик только тогда, когда event.target является текущим элементом.
- Событие .once сработает только один раз
- .passive сообщает браузеру, что вы не хотите блокировать поведение событий по умолчанию.
Модификаторы для v-модели
-
.lazy преобразуется в ресинхронизацию в событии изменения через этот модификатор
-
.number автоматически преобразует введенное пользователем значение в числовой тип.
-
.trim автоматически фильтрует начальные и конечные пробелы, введенные пользователем.
Модификаторы для событий клавиатуры
- .enter
- .tab
- .delete (захватывает клавиши «удалить» и «возврат»)
- .esc
- .space
- .up
- .down
- .left
- .right
системные клавиши-модификаторы
- .ctrl
- .alt
- .shift
- .meta
модификатор кнопки мыши
- .left
- .right
- .middle
34 Принцип компиляции шаблона Vue
Процесс компиляции Vue — это процесс преобразования шаблона в функцию рендеринга, который делится на следующие три шага.
第一步是将 模板字符串 转换成 element ASTs(解析器)
第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)
Соответствующий код выглядит следующим образом
export function compileToFunctions(template) {
// 我们需要把html字符串变成render函数
// 1.把html代码转成ast语法树 ast用来描述代码本身形成树结构 不仅可以描述html 也能描述css以及js语法
// 很多库都运用到了ast 比如 webpack babel eslint等等
let ast = parse(template);
// 2.优化静态节点
// 这个有兴趣的可以去看源码 不影响核心功能就不实现了
// if (options.optimize !== false) {
// optimize(ast, options);
// }
// 3.通过ast 重新生成代码
// 我们最后生成的代码需要和render函数一样
// 类似_c('div',{id:"app"},_c('div',undefined,_v("hello"+_s(name)),_c('span',undefined,_v("world"))))
// _c代表创建元素 _v代表创建文本 _s代表文Json.stringify--把对象解析成文本
let code = generate(ast);
// 使用with语法改变作用域为this 之后调用render函数可以使用call改变this 方便code里面的变量取值
let renderFn = new Function(`with(this){return ${code}}`);
return renderFn;
}
Подробное объяснение принципа компиляции шаблонапортал
35 Как реализованы крючки жизненного цикла
Основная реализация хука жизненного цикла Vue заключается в использовании модели публикации-подписки, чтобы сначала подписаться на хук жизненного цикла, переданный пользователем (сохраненный во внутреннем массиве), а затем выполнить соответствующий метод хука (публикация) один раз в процессе. создания экземпляра компонента.
Соответствующий код выглядит следующим образом
export function callHook(vm, hook) {
// 依次执行生命周期对应的方法
const handlers = vm.$options[hook];
if (handlers) {
for (let i = 0; i < handlers.length; i++) {
handlers[i].call(vm); //生命周期里面的this指向当前实例
}
}
}
// 调用的时候
Vue.prototype._init = function (options) {
const vm = this;
vm.$options = mergeOptions(vm.constructor.options, options);
callHook(vm, "beforeCreate"); //初始化数据之前
// 初始化状态
initState(vm);
callHook(vm, "created"); //初始化数据之后
if (vm.$options.el) {
vm.$mount(vm.$options.el);
}
};
Подробное объяснение реализации жизненного циклапортал
36 Сценарии и принципы использования функциональных компонентов
Отличие функциональных компонентов от обычных компонентов
1.函数式组件需要在声明组件是指定 functional:true
2.不需要实例化,所以没有this,this通过render函数的第二个参数context来代替
3.没有生命周期钩子函数,不能使用计算属性,watch
4.不能通过$emit 对外暴露事件,调用事件只能通过context.listeners.click的方式调用外部传入的事件
5.因为函数式组件是没有实例化的,所以在外部通过ref去引用组件时,实际引用的是HTMLElement
6.函数式组件的props可以不用显示声明,所以没有在props里面声明的属性都会被自动隐式解析为prop,而普通组件所有未声明的属性都解析到$attrs里面,并自动挂载到组件根元素上面(可以通过inheritAttrs属性禁止)
Преимущества 1. Поскольку функциональные компоненты не требуют создания экземпляров, не имеют состояния и жизненного цикла, производительность рендеринга выше, чем у обычных компонентов. 2. Структура функциональных компонентов проще, а структура кода понятнее.
используемые сцены:
Простой компонент представления, используемый в качестве компонента-контейнера, такой как router-view, является функциональным компонентом.
«Компонент высшего порядка» — используется для получения компонента в качестве параметра и возврата упакованного компонента.
Соответствующий код выглядит следующим образом
if (isTrue(Ctor.options.functional)) {
// 带有functional的属性的就是函数式组件
return createFunctionalComponent(Ctor, propsData, data, context, children);
}
const listeners = data.on;
data.on = data.nativeOn;
installComponentHooks(data); // 安装组件相关钩子 (函数式组件没有调用此方法,从而性能高于普通组件)
37 Можете ли вы рассказать о принципах реализации часто используемых режимов маршрутизации в vue-router?
хэш-режим
-
Значение location.hash на самом деле стоит после # в URL-адресе.Его характеристики таковы: хотя хэш появляется в URL-адресе, он не будет включен в HTTP-запрос и не повлияет на серверную часть, поэтому изменение хеша не перезагружать страницу.
-
Вы можете добавить события прослушивателя для изменений хэша
window.addEventListener("hashchange", funcRef, false);
Каждый раз, когда хэш (window.location.hash) изменяется, в историю доступа браузера будет добавляться запись.Используя указанные выше характеристики хэша, интерфейсная функция маршрутизации «обновление представления без повторного запроса страницы» можно реализовать.
Особенности: хорошая совместимость, но не красивая
режим истории
Воспользуйтесь преимуществами новых методов pushState() и replaceState() в интерфейсе истории HTML5.
Эти два метода применяются к станции истории браузера.На основе существующих назад, вперед и вперед они обеспечивают функцию модификации истории. У этих двух методов есть общая черта: когда они вызываются для изменения стека истории браузера, хотя текущий URL-адрес изменился, браузер не будет обновлять страницу. «Страница» обеспечивает основу.
Особенности: Хоть и красиво, но в рефреше появится 404, а бэкенд надо настраивать
38 Вы понимаете алгоритм сравнения?
Рекомендуется смотреть непосредственно на подробное объяснение алгоритма diffпортал
Ссылка на сериал (будет обновлена позже)
- Написанный от руки исходный код Vue2.0 (1) — принцип адаптивных данных
- Рукописный исходный код Vue2.0 (2) - принцип компиляции шаблона
- Рукописный исходный код Vue2.0 (3) — принцип начального рендеринга
- Рукописный исходный код Vue2.0 (четыре) — принцип обновления рендеринга
- Рукописный исходный код Vue2.0 (5) - принцип асинхронного обновления
- Рукописный исходный код Vue2.0 (6) - принцип алгоритма diff
- Рукописный исходный код Vue2.0 (7) - Принцип микширования
- Рукописный исходный код Vue2.0 (8)-компонентный принцип
- Рукописный исходный код Vue2.0 (9) - принцип свойства прослушивания
- Рукописный исходный код Vue2.0 (10) — Принцип вычисляемых свойств
- Рукописный исходный код Vue2.0 (11) — принцип глобального API
- Самые полные вопросы интервью Vue + подробные ответы
- Рукописный исходный код vue-router
- Рукописный исходный код vuex
- Рукописный исходный код vue3.0
Группа передовых рыболовных технологий Brother Shark
Приветствую всех на технических биржахСвязь