Адрес базовой базы знаний (постоянно обновляется):Наггетс.Талант/пост/686307…
webpack
что такое загрузчик?
Загрузчик — это, по сути, функция, в которой преобразуется полученный контент и возвращается преобразованный результат. Поскольку Webpack знает только JavaScript, Loader становится переводчиком, переводя и предварительно обрабатывая другие типы ресурсов.
Загрузчики настраиваются в module.rules: тестируйте и пользуйтесь. test может получить регулярное выражение, и только модули, соответствующие регулярному выражению, могут использовать это правило; use может получить массив, содержащий загрузчики, используемые правилом.
Обычные загрузчики:
- загрузчик файлов позволяет нам вводить ресурсы изображений, такие как png\jpg, в файлы JS.
- url-loader похож на file-loader, разница только в том, что пользователь может установить порог размера файла, когда он больше порога, возвращает тот же publicPath, что и file-loader, а когда меньше порога , он возвращает кодировку файла base64.
- style-loader css-loader Среди них css-loader обрабатывает контент, импортированный импортом require() @import/url в js; style-loader отвечает за вставку стилей в DOM, вставляя тег стиля в заголовок и записывая стиль в innerHTML этого тега.
- sass-loader конвертирует scss в css
- less-loader меньше конвертирует в css
- Промежуточный мост babel-loader сообщает веб-пакету, как обрабатывать js, вызывая API в babel/core.
- babel — это цепочка инструментов, в основном используемая для преобразования кода версии ECMAScript 2015+ в обратно совместимый синтаксис JavaScript, чтобы его можно было запускать в текущих и более старых версиях браузеров или других средах.
- @babel/core — основная библиотека babel, все основные API находятся в этой библиотеке, эти API вызываются babel-loader
- Основными полями конфигурации @babel/preset-env являются useBuiltIns и target; target указывает рабочую среду компилируемого кода, которая может быть браузером или узлом. Пока установлены соответствующие поля, он может следовать правилам и избегать соответствующего синтаксиса и API. useBuiltIns: нет необходимости вручную импортировать '@babel/polyfill'; новые API, используемые бизнес-кодом, заполняются по мере необходимости.
"@babel/env", { targets: { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] //表示兼容市场占有率>1%,浏览器的最新两个版本,ie8以下不兼容 }, useBuiltIns: "usage", },- @ Babel / PRESET-ENV просто предоставляет правила для грамматического преобразования, но не компенсирует некоторые новые функции, отсутствующие в браузере.
просто @babel/preset-env
Настроил @babel/polyfill "useBuiltIns": "использование"
пользовательский загрузчиксегмент fault.com/ah/119000001…
Plugin
Плагин — это плагин. Основанный на структуре потока событий Tapable, плагины могут расширять функции Webpack. В течение жизненного цикла Webpack будет транслироваться множество событий. Плагин может прослушивать эти события и изменять выходные результаты через API, предоставляемый Webpack в нужное время.
Часто используемые плагины:
- html-webpack-plugin автоматически генерирует файлы HTML5 и вводит такие файлы, как js, упакованные webpack.
- clean-webpack-plugin используется для очистки папки dist перед упаковкой
- модуль hot-module-replacement-plugin подключаемый модуль горячей замены, а именно HMR, webpack4 поставляется с подключаемым модулем, не требует установки, используйте с devServer в режиме разработки
- mini-css-extract-plugin извлекает CSS в отдельные файлы по аналогии с extract-text-webpack-plugin (webpack4 устарел). По сравнению с двумя преимуществами mini-css-extract-plugin:
- Асинхронная загрузка
- отсутствие дублирования компиляции (производительность)
- проще в использовании
- конкретный CSS
- PurgecssPlugin может удалить неиспользуемый CSS, обычно используемый в сочетании с glob и glob-all.
- оптимизация-css-assets-webpack-plugin для минимизации CSS
- commons-chunk-plugin используется для извлечения общего кода в js (webpack4 устарел)
Вставьте одно предложение: преимущества извлечения общего кода модуля: повторная упаковка модуля уменьшается в процессе разработки, что может повысить скорость разработки; уменьшить общий объем ресурсов; код после разумной фрагментации может более эффективно использовать кэш клиента. - split-chunks-plugin используется для извлечения общего кода в js. встроенный плагин webpack4. Преимущества над плагином commons-chunk:
- От императивного к декларативному
- Оптимизирована проблема асинхронного извлечения общего кода модуля плагином commons-chunk (общий модуль асинхронного кода не может быть правильно извлечен).
- webpack-bundle-analyzer визуализирует размер выходных файлов webpack
Tickets.WeChat.QQ.com/Yes/WF W_l0QS1… блог woo woo woo.cn на.com/Overworked/Arch… blog.CSDN.net/WeChat_4390… Блог woowoo.cn на.com/SU South/afraid/1…
Принцип горячего обновления WebPack
Командная строка самого webpack не поддерживает HMR. Мы можем использовать webpack-dev-server с HotModuleReplacementPlugin, чтобы включить HMR:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
hot: true
}
}
В локальной среде разработки браузер является клиентом, а webpack-dev-server (WDS) — нашим сервером. Суть HMR в том, что клиент тянет обновленные ресурсы с сервера (если быть точным, HMR тянет не весь файл ресурсов, а чанк diff, то есть часть чанка, которую нужно обновить.
На самом деле, между WDS и браузером поддерживается веб-сокет, при изменении локального ресурса WDS отправит событие обновления в браузер и принесет хэш этой конструкции, чтобы клиент мог сравнить с предыдущим ресурсом. Клиент сравнивает, изменился ли файл в соответствии с хеш-значением. Если есть разница, клиент делает запрос к WDS, чтобы получить список файлов, т.е. какие модули изменились. Затем клиент может использовать эту информацию, чтобы продолжать получать добавочные обновления фрагмента от WDS.
После того, как клиент получает обновление чанка, возникает очень важный вопрос: как клиент обрабатывает эти добавочные обновления? Какие состояния нужно сохранить, а какие обновить? Его можно обрабатывать в соответствии с его собственной сценой через соответствующие API (например, module.hot.accept). HMR, такие как react-hot-loader и vue-loader, также реализуются с помощью этих API.
процесс сборки вебпака
Работающий процесс Webpack является последовательным процессом, от начала до конца последовательно выполняются следующие процессы:
-
Параметры инициализации:Чтение из файла конфигурации и инструкции Shell и консолидированных параметров для получения окончательных параметров.
-
Начать компиляцию:Инициализируйте объект Compiler с параметрами, полученными на предыдущем шаге, загрузите все настроенные плагины и выполните метод запуска объекта, чтобы начать компиляцию.
-
Определяем вход:Найти все входные файлы на основе записи в конфигурации
-
Скомпилируйте модуль:Начиная с файла записи, вызовите все настроенные загрузчики для преобразования модуля, а затем найдите модули, от которых зависит модуль, и повторите этот шаг, пока все файлы, от которых зависит запись, не будут обработаны на этом шаге.
-
Завершите компиляцию модуля:После перевода всех модулей с помощью Loader на шаге 4 мы получаем окончательный контент каждого модуля после перевода и зависимости между ними.
-
Выходной ресурс:В соответствии с зависимостями между записью и модулем соберите их в чанки, содержащие несколько модулей, а затем преобразуйте каждый чанк в отдельный файл и загрузите его в выходной список.Этот шаг — последний шанс изменить выходное содержимое.
-
Вывод сделан:После определения выходного содержимого определите выходной путь и имя файла в соответствии с конфигурацией и запишите содержимое файла в файловую систему.
В приведенном выше процессе Webpack будет транслировать определенное событие в определенный момент времени, подключаемый модуль будет выполнять определенную логику после прослушивания интересующего события, а подключаемый модуль может вызывать API, предоставленный Webpack, для изменения текущего результат вебпака.
просто скажи:
-
Инициализация: Запустите сборку, прочитайте и объедините параметры конфигурации, загрузите плагин, создайте экземпляр компилятора.
-
Компиляция: начиная с записи, последовательно вызывайте соответствующий загрузчик для каждого модуля, чтобы преобразовать содержимое файла, а затем найдите модуль, от которого зависит модуль, и рекурсивно скомпилируйте его.
-
Вывод: объедините скомпилированные модули в куски, преобразуйте куски в файлы и выведите их в файловую систему.
Статья об анализе исходного кода:nuggets.capable/post/684490…
module chunk bundle
- модуль: каждый исходный файл, все в webpack является модулем
- Чанк: комбинация нескольких модулей, где вы можете установить фрагменты, такие как вход, импорт(), раздельные фрагменты.
- комплект: окончательный выходной файл
Оптимизация эффективности упаковки
- Оптимизируйте babel-loader: включите кэширование и уточните область упаковки
- IgnorePlugin: избегайте ссылок на бесполезные модули
- noParse позволяет избежать повторной упаковки
- Мультипроцессная упаковка happyPack
- ParallelUglyPlugin Многопроцессное сжатие JS
- Автоматическое обновление
- Автоматические обновления (генерация нового кода, без обновления страницы, без потери состояния): webpack-dev-server и HotModuleReplacementPlugin
- DllPlugin: Одна и та же версия собирается только один раз, без повторной сборки каждый раз.
Оптимизировать выходной код
- Небольшие изображения конвертируются в кодировку base64 через url-loader.
- Пакет плюс кеш-хеш-попадание (contentHash)
- ленивая загрузка
- Извлечь общий код (splitChunks)
- IgnorePlugin
- Ускоряйтесь с CND
- Использовать производственный режим
- Scope Hoisting: меньший размер кода, меньше возможностей для создания функций, лучшая читаемость кода. (МодульКонкатенацияПлагин)
- сжатие gzip (CompressionWebpackPlugin)
Javascript расширенный
цикл событий
Задачи JS делятся на синхронные задачи и асинхронные задачи:
- Очереди задач делятся на очереди синхронных задач и очереди асинхронных задач;
- Когда код выполняется, если он сталкивается с синхронным кодом, он будет напрямую помещен в очередь синхронных задач и выполнен последовательно;
- При обнаружении асинхронного кода (например, setTimeout, setInteval) он будет помещен непосредственно в очередь асинхронных задач;
- При выполнении очереди синхронных задач задачи из очереди асинхронных задач будут помещены в очередь синхронных задач одновременно и выполнены последовательно.
Очередь задачи JS разделена на: Macro Task: Settimeout Setinterval MicroTask: обещание. Тот метод. Обратите внимание, что новое обещание () синхронно и будет выполнено немедленно.
Примечание. Теперь существует три очереди: очередь синхронизации (также известная как стек выполнения), очередь макрозадач, очередь микрозадач. Поэтому для этого механизма механизм событийного цикла js должен быть таким:
- Встречайте синхронный код, по очереди помещайте его в синхронную очередь и выполняйте.
- Когда setTimeout setInterval встречается, он будет помещен в очередь задач макроса.
- Если встречается .then, он будет рассматриваться как микрозадача и помещаться в очередь микрозадач.
- После выполнения очереди синхронизации перейдите к микрозадаче, чтобы получить задачу, пока очередь микрозадачи не опустеет. Затем проверьте очередь макрозадач, перейдите в очередь макросов, чтобы получить задачи, и после выполнения каждой макрозадачи она перейдет в очередь микрозадач, чтобы запустить ее снова, чтобы увидеть, есть ли новые микрозадачи, а затем очистить микро задания, если они есть. Этот цикл по очереди.
Синхронный код -> микрозадачи (выполнить все) -> макрозадачи (выполнить одну) -> микрозадачи (выполнить все) -> макрозадачи (выполнить одну)
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
上述代码执行顺序:
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
Примечание. Код синхронизации в теле функции async1(){...} фактически эквивалентен коду new Promise(resolve=>{...; resolve()}). является синхронным кодом. Встреча с await эквивалентна new Promise().then(res=>{...}); Это микрозадача, которая будет помещена в очередь микрозадач для выполнения. Это то же самое, что описано в моем другом сообщении в блогеНаггетс.Талант/пост/688367…
Взгляните еще раз на этот самодельный пример:
async function asyncf1() {
console.log("async1 start");
await asyncf2();
console.log("async1 middle")
return "hello async"
}
async function asyncf2() {
console.log("async2 start");
return "hello async222"
}
asyncf1().then(res=>{
console.log(res);
});
console.log("tongbu");
Порядок выполнения:
async1 start
async2 start
tongbu
async1 middle
hello async
Приложение Обещания
Рукописное обещание
Обещаю загрузку картинок
function loadImg(url){
return new Promise((resolve, reject) => {
var imgDom = document.createElement("img");
imgDom.src = url;
//图片加载成功回调
imgDom.onload = ()=>{
resolve(imgDom);
}
//图片加载失败回调
imgDom.onerroe = (error)=>{
reject(error)
}
document.body.appendChild(imgDom);
})
}
const url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603026217111&di=fb11837b4633e99c0b71ff48b5213cf1&imgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F56%2F12%2F01300000164151121576126282411.jpg";
loadImg(url).then(res=>{
console.log(res.width);
}, error=>{
console.log(error)
})
Обещание нативного запроса XHR
function promiseGet(url) {
return new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
xhr.onreadystatechange = function () {
// 4 响应已完成; 0:请求未初始化,还没有调用 open()。 1:请求已经建立,但是还没有发送,还没有调用 send()。
// 2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)。 3:请求在处理中;
if(xhr.readyState === 4){
// 成功
if(xhr.status===200){
resolve(xhr.response);
}
}
}
xhr.onerror = ()=>{
reject(xhr.response);
}
xhr.upload.onprogress = function (e) {
const percent = (e.loaded / e.total) * 100;
console.log("percent: " + percent)
}
})
}
const url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603026217111&di=fb11837b4633e99c0b71ff48b5213cf1&imgtype=0&src=http%3A%2F%2Fa0.att.hudong.com%2F56%2F12%2F01300000164151121576126282411.jpg";
promiseGet(url).then(res=>{
console.log(res);
}).catch(error=>{
console.log("error...", error)
})
Рукописная модель публикации-подписки
class EventHub{
cache = {};
on(eventName, fn){
this.cache[eventName] = this.cache[eventName] || [];
this.cache[eventName].push(fn);
}
emit(eventName, data){
(this.cache[eventName]||[]).forEach(fn=>fn&&fn(data));
}
off(eventName, fn){
const index = indexOf(this.cache[eventName], fn);
if(index==-1){
return;
}
this.cache[eventName].splice(index, 1);
}
}
function indexOf(arr, item){
if(arr===undefined){
return -1;
}
let index = -1;
for(let i=0;i<arr.length;i++){
if(arr[i]===item){
index = i;
break;
}
}
return index;
}
Vue
опускать сокращения
аббревиатура v-bind
<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>
аббревиатура v-on
<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>
Разница между v-show и v-if
- v-show — это переключатель CSS, display: none; v-if — это полное уничтожение и воссоздание, оно не будет создано при v-if="false"
- Частое переключение — это V-Show; используйте V-IF, когда времени на переключение меньше
метод привязки класса
- Метод объекта v-bind:class="{'orange': isRipe}" //оранжевое имя класса, isRipe переменная
- Метод массива v-bind:class="['class1', class2]" //class1 — это имя класса, class2 — это переменная
- Встроенный v-bind:style="{color: color}"
Почему данные компонента — это функция
Почему данные в компоненте должны быть функцией, а затем возвращать объект, а в новом экземпляре Vue данные могут быть объектом?
Поскольку компоненты используются для повторного использования, объекты в JS являются ссылочными типами, поэтому область действия не изолирована, а новые экземпляры Vue не будут использоваться повторно, поэтому проблем со ссылками на объекты не возникает.
смотри и вычисляй
- watch: используйте watch, когда изменение данных влияет на несколько данных; пример: данные поиска
- Элементы конфигурации часов: обработчик глубокий немедленный
- глубоко: следует ли слушать глубоко
- немедленно: следует ли выполнять немедленно; true означает, что функция прослушивателя также должна выполняться, когда значение связывается в первый раз. Например, когда родительский компонент динамически передает значение дочернему компоненту, когда свойства дочернего компонента впервые получают значение по умолчанию от родительского компонента, функция также должна быть выполнена.В это время вам нужно установить сразу к истине
- вычисленный: вычисление используется, когда на атрибут влияют несколько атрибутов; пример: расчет корзины покупок
keep-alive
keep-alive — это встроенный компонент Vue, в основном используемый для сохранения состояния компонента или предотвращения повторного рендеринга.
- Props:
- include: Строка или регулярное выражение. Кэшируются только компоненты с совпадающими именами.
- исключить: Строка или регулярное выражение. Любые компоненты, имена которых совпадают, не будут кэшироваться.
<keep-alive include="a">
<component>
<!-- name 为 a 的组件将被缓存! -->
</component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive exclude="a">
<component>
<!-- 除了 name 为 a 的组件都将被缓存! -->
</component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive include="a">
<router-view>
<!-- 只有路径匹配到的视图 a 组件会被缓存! -->
</router-view>
</keep-alive>
v-model
v-model — это синтаксический сахар, v-model на компоненте эквивалентен prop: value and input event.
<testComp v-model="initMsg"></testComp>
//等价于
<testComp v-bind:value="initMsg" v-on:input="initMsg=$event"></testComp>
Однонаправленный поток данных
Все реквизиты образуют одностороннюю связь между родительскими и дочерними реквизитами: обновления родительских реквизитов передаются дочерним компонентам, но не наоборот. Это предотвращает случайное изменение родительского состояния дочерними компонентами. Кроме того, каждый раз, когда родительский компонент изменяется, все реквизиты в дочернем компоненте будут обновляться до последнего значения. Это означает, что вы не должны изменять свойства внутри дочернего компонента. Если вы это сделаете, Vue выдаст предупреждение в консоли браузера.
компонент связи
компонент родитель-потомок
родительский компонент черезpropsПередайте данные дочерним компонентам, а дочерние компоненты передают事件Отправить информацию в родительский компонент.
//子组件 Item.vue
export default {
name: "Item",
props: {
content: {
type: String,
default: "item"
}
},
methods: {
change(){
this.$emit('changeContent', "new msg");
}
}
}
<!-- 父组件 -->
<Item :content="content" v-on:changeContent="fChange"></Item>
родительский компонентv-onПодписаться на событияchangeContent, узел$emitИнициировать события и отправлять информацию.
любой компонент
Используйте новый Vue(), чтобы вывести событие транзитной станции, компонент проходитevent.$emit("fnName", data)публиковать события;
другие компоненты черезevent.$on("fnName", callback)Подписаться на событияfnName, и активируйте функцию обратного вызоваcallback.
//event.js
import Vue from 'vue';
export default new Vue();
Сообщение событие:
//组件A
change(){
event.$emit("changeVersion", "3.0");
},
Подписка на любой другой компонентchangeVersionпроисшествии и помнить о последующей работе вbeforeDestroyОтписаться от мероприятия.
mounted(){
event.$on("changeVersion", this.alertVersion)
},
beforeDestroy(){
event.$off("changeVersion")
},
Жизненный цикл
- До и после создания
- И созданные данные, и методы были инициализированы; если вы хотите использовать методы в методах или манипулировать данными в данных, вы можете работать на этом этапе как можно раньше.
- До и после загрузки
- смонтированный означает, что экземпляр Vue был инициализирован.В это время компонент покидает фазу создания и переходит в фазу выполнения. Если мы хотим манипулировать DOM-узлами на странице через плагин, это можно сделать на этом этапе как можно раньше.
- До и после обновления
- beforeUpdate: когда этот хук выполняется, данные, отображаемые на странице, все еще старые, данные в данных обновляются, и страница не была синхронизирована с последними данными.
- обновлено: данные, отображаемые на странице, и данные в данных были синхронизированы, и они являются последними
- До и после разрушения
- beforeDestory: Экземпляр Vue перешел в фазу уничтожения из фазы выполнения.В это время доступны все данные и методы, директивы, фильтры... не совсем уничтожен
- уничтожено: В настоящее время все данные и методы, директивы, фильтры... находятся в недоступном состоянии. Компонент уничтожен.
Жизненный цикл родительско-дочернего компонента
Загрузить процесс рендеринга
родитель beforeCreate -> созданный родитель -> родитель beforeMount -> дочерний beforeCreate -> созданный дочерний элемент -> дочерний beforeMount -> смонтированный дочерний элемент -> смонтированный родительский элемент
Процесс обновления подкомпонента
родитель до обновления -> дочерний перед обновлением -> дочерний обновлен -> родительский обновлен
процесс разрушения
родитель перед уничтожением -> дочерний перед уничтожением -> дочерний уничтожен -> родитель уничтожен
Что нужно сделать, бефоредет
- Отменить привязку пользовательских событий
event.$off - очистить таймер
- Отменить привязку пользовательских событий DOM, таких как события в окне.
Рекомендации по обнаружению изменений
Вопрос об объекте
В версии Vue2.0 принцип ответа объектных данных заключается в использовании Object.defineProperty для отслеживания того, было ли изменено содержимое ключа объекта, и невозможно отследить вновь добавленные свойства и удаленные свойства.
var vm = new Vue({
el: '#el',
methods: {
action(){
//检测不到
delete this.obj.name;
//检测不到
this.obj.age = 12;
}
},
data: {
obj: {
name: 'zhangsan'
}
}
})
Вопрос про массивы
В версии vue2.0 принцип реагирования массива заключается в перехвате 7 методов данных (включая push, pop, shift, unshift, splice, sort, reverse) вместо прослушивания каждого ключа (массива) в соответствии с Object. defineProperty — это порядковый номер, соответствующий модификации содержимого. Затем мы можем напрямую изменить содержимое, соответствующее индексу массива, и использовать length для изменения длины массива, который нельзя отследить, и нельзя реализовать динамический отклик данных.
//无法被追踪监测到
this.list[0] = 12;
//无法被追踪检测到
this.list.length = 0;
В исходном коде vue2.0 принцип ответа массива следующий:
//工具函数
function def(obj, key, val, enumerable){
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
const hasProto = '__proto__' in {};
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(method){
const original = arrayProto[method];
Object.defineProperty(arrayMethods, method, {
value: function mutator(...args){
console.log("here")
return original.apply(this, args);
},
enumerable: false,
writable: true,
configurable: true
})
});
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
function copyAugment(target, src, keys){
for(let i=0;i<keys.length;i++){
const key = keys[i]
def(target, key, src[key]);
}
}
const arr = [2, 5, 13, 90];
if(Array.isArray(arr)){
//支持 __proto__
if(hasProto){
arr.__proto__ = arrayMethods;
} else{
copyAugment(arr, arrayMethods, arrayKeys);
}
}
arr.push(4);
console.log(arr);
console.log(arrayMethods);
Видно, что есть два случая в зависимости от того, поддерживает ли браузер запись __proto__. Если браузер поддерживает метод записи __proto__, он пропустит перехваченные 7 методов через arr._proto_= arrayMethods; помещает 7 методов перехвата в объект-прототип arr. Однако, если он не поддерживается, задайте 7 методов перехвата непосредственно в объекте arr. Таким образом, когда пользователь манипулирует массивом с помощью любого из 7 методов массива, его можно отслеживать.
$nextTick
Vue не обновляет DOM напрямую при наблюдении за изменениями данных, а открывает очередь (микрозадачу) для обновления DOM. Поэтому, если вы используете цикл for для динамического изменения данных 100 раз, он применит только последнее изменение, без этого механизма DOM будет перерисовываться 100 раз. (Vue.js использует асинхронную очередь обновлений для обновления DOM)
$ NextTick получает функцию обратного вызова в качестве параметра, его роль - задержать обратный вызов до следующего цикла обновления DOM. Поместите функцию обратного вызова в очередь async. Vue будет преимущественно использовать нативное обещание. Затем, мутацияОбсервер и Setimmediate в соответствии с текущей средой браузера. Если они не поддерживаются, вместо этого будет использоваться SettimeOut.
В исходном коде vue2.5 схема понижения макрозадач такова: setImmediate, MessageChannel, setTimeout
Принцип реализации метода nextTick vue:
- Vue использует асинхронную очередь для управления обновлением DOM и обратным вызовом nextTick для последовательного выполнения.
- Благодаря высокому приоритету микрозадачи могут гарантировать, что микрозадачи в очереди будут выполнены до цикла обработки событий.
- Учитывая проблемы совместимости, vue разработала план перехода с микрозадачи на макрозадачу.
//模拟 nextTick
const callbacks = [];
//变量控制 microTimerFunc 一次事件循环中只执行一次。
let pending = false;
function flushCallbacks(){
pending = false;
const copies = callbacks.slice(0);
callbacks.length = 0;
for(let i = 0;i < copies.length; i++){
copies[i]()
}
}
let microTimerFunc;
const p = Promise.resolve();
microTimerFunc = ()=>{
p.then(flushCallbacks)
}
function nextTick(cb, ctx){
callbacks.push(()=>{
if(cb){
cb.call(ctx)
}
})
if(!pending){
pending = true;
microTimerFunc()
}
}
//测试一下
nextTick(function(){
console.log(this.name);
}, {name: 'Berwin'});
console.log("start...");
nextTick(function(){
console.log(this.name);
}, {name: 'lisi'});
алгоритм сравнения в vue
Принцип обнаружения данных Vue заключается в том, чтобы знать, где используются определенные данные, и когда данные изменяются, он может напрямую уведомить соответствующий наблюдатель об изменении. Итак, зачем вам нужно использовать алгоритм diff? Поскольку степень детализации слишком мала, будет много наблюдателей, наблюдающих за определенным состоянием одновременно, будут некоторые накладные расходы на память и некоторые накладные расходы на отслеживание зависимостей, поэтому Vue.js 2.0 принимает решение со средней степенью детализации, а обнаружение состояния больше не дорабатывается до определенного Это конкретный узел, а компонент.Компонент рендерит представление через виртуальный DOM, что может сильно уменьшить количество зависимостей и количество наблюдателей.
Что такое виртуальный узел?
Виртуальный узел (vnode) — это обычный объект в Javascript, и в свойствах этого объекта хранятся некоторые данные, необходимые для создания узла DOM.
В версии Vue.js 2.0 при обновлении и рендеринге компонента вновь созданный виртуальный узел будет использоваться для сравнения виртуального узла, кэшированного при предыдущем рендеринге, а затем будет обновлен только реальный DOM-узел, который необходимо обновить. в соответствии с результатом сравнения, таким образом избегая ненужных манипуляций с DOM, сохраняя некоторую производительность. Это алгоритм сравнения, алгоритм сравнения.
При использовании алгоритма сравнения для сравнения старых и новых узлов сравнение будет выполняться только на одном уровне и не будет сравниваться между уровнями.
<div>
<p>123</p>
</div>
<div>
<span>456</span>
</div>
Приведенный выше код сравнивает два div на одном уровне и p и span на втором слое соответственно, но не сравнивает div и span. Очень яркая картина видна в другом месте:
Функции выполнения исходного кода алгоритма diff: patch (oldVnode, vnode) -> patchVnode (oldVnode, vnode) -> updateChildren (parentElm, oldCh, newCh)
подробнее:nuggets.capable/post/684490…
Зачем использовать ключ в v-for
Согласно вышеизложенномуdiffАлгоритм процесса, который мы знаем, vue будет основан на виртуальном DOM.tagа такжеkeyчтобы решить, можно ли повторно использовать настоящие узлы DOM. если в v-forне используется вkey,ноdiffТолько по алгоритмуtagчтобы определить, следует ли повторно использовать настоящий узел DOM. еслиtagНикаких изменений, содержимое было изменено, в это время будут проблемы,vueОн будет глупо думать, что настоящий DOM доступен, и будет напрямую повторно использовать предыдущий настоящий DOM. См. пример ниже:
В этом примере поspan、input、buttonТри компонента, созданные с помощью меток. v-forне используется вkeyПри обновлении страницы старый виртуальный DOM — [1, 2, 3], новый — [1, 3]. Первые данные будут использоваться повторно, вторые данные не являются уникальным признаком из-за каждого компонентаidтак какkey,diffПроцесс алгоритма сначала сравнит вторые данные старого виртуального дома со вторыми данными нового виртуального дома.tagТо же самое будет напрямую использовать реальный узел dom. Информация о странице неверна.
Итак, использование ключа в v-for может:
- В алгоритме виртуального DOM VNode идентифицируется при сравнении старых и новых узлов.
- Без ключей Vue использует алгоритм, который сводит к минимуму добавление или удаление элементов и пытается максимально восстановить/повторно использовать элементы одного и того же типа. (Повторно используйте настоящий элемент DOM с тем же тегом на месте).
- Если используется ключ, элементы с одинаковым значением ключа используются повторно напрямую.
- Компоненты с ключами могут запускать эффекты перехода и запускать цикл объявления компонентов.
детальЕсли вы хотите определить уникальность компонента, пустьdiffАлгоритм более точный, пожалуйста, используйте独特的 keyВместо использования индекса в цикле for или использования random.
Процесс рендеринга Vue
Первый рендеринг:
- Шаблон синтаксического анализа
renderфункция - Триггер реагирует, слушайте
dataустановщик свойств - воплощать в жизнь
renderфункция, будет генерироватьvnodeи визуализировать страницу
Обновление рендеринга:
- Изменить данные, вызвать
setter - сделай это снова
renderфункция для создания новыхvnode - Алгоритм diff сравнивает старый и новый
vnode, обновите страницу
Принцип Vuex
Vuex извлекает общее состояние компонентов и управляет им в глобальном одноэлементном шаблоне. Ядром каждого приложения Vuex является магазин. Хранилище — это, по сути, контейнер, который содержит большую часть состояния вашего приложения.Vuex отличается от чистого глобального объекта двумя способами:
- Хранилище состояния Vuex является реактивным. Когда компонент Vue считывает состояние из хранилища, если состояние в хранилище изменяется, соответствующий компонент будет соответствующим образом эффективно обновляться.
- Вы не можете напрямую изменить состояние в хранилище. Единственный способ изменить состояние в хранилище — это явно зафиксировать мутации. Это позволяет нам легко отслеживать каждое изменение состояния.
Принцип реализации Vuex заключается в преобразовании данных состояния в адаптивные после передачи new Vue() . В то же время данные, определенные в геттере, реализуются через вычисляемое свойство нового Vue, и они будут пересчитываться только при изменении его зависимого значения.
Внедрите Vuex самостоятельно с помощью Vue
Мы можем настроить MyStore.js, который определяет элементы данных, совместно используемые проектом, и методы изменения данных. Затем смонтируйте его в корневые данные.
// MyStore.js
export default class{
constructor(){
this.count = 10;
let self = this;
this.mutations = {
incrementCount(){
self.count++;
}
}
}
}
В проекте представлено:
import MyStore from './MyStore.js';
var app = new Vue({
el: "#app",
data: {
myStore: new MyStore()
}
})
Таким образом, мы можем получить доступ к глобальной переменной count через this.$root.myStore.count в компоненте. Измените переменные через this.$root.myStore.mutations.incrementCount();.
Разница между действием и мутацией в Vuex
- Асинхронные операции обрабатываются в действии, и мутации лучше не делать. (Данные страницы асинхронной операции обработки мутаций будут изменены, но значение в devtools по-прежнему является исходным и не было изменено. Существует несогласованность данных, и изменения данных невозможно отследить.)
- мутация выполняет атомарные операции
- Действия могут интегрировать несколько мутаций
Vue Router
хэш-режим
Vue Router по умолчанию использует хэш-режим в соответствии с URL-адресом.hashИзменение значения переключает компонент для достижения функции переключения модуля. При этом вся страница не обновляется.
const router = new VueRouter({
mode: 'hash',
routes: [...]
})
Принцип маршрутизации в хэш-режиме заключается в отслеживанииwindowизhashchangeСобытие, изменение хеш-значения в URL вызовет событие. И когда мы обновим страницу, мы не будем инициировать новый запрос ресурсов на серверную часть,/index.html#userЗапрошенный адрес совпадает с/index.htmlэто то же самое.
<p id="content">default</p>
<script>
window.location.hash = "qq";
window.addEventListener('hashchange', ()=>{
document.getElementById("content").innerHTML = window.location.hash;
})
</script>
режим истории
Если вы считаетеhashмодальный#Уродливо, Vue Router также предоставляет режим истории
const router = new VueRouter({
mode: 'hash',
routes: [...]
})
Принцип обеспечивается историей в HTML5pushState、replaceStateэти два API. Они предоставляют методы для управления стеком истории браузера.pushState、replaceStateВозможность изменить URL-адрес браузера без загрузки страницы.
<button id="changePage1">page1</button>
<button id="changePage2">page2</button>
<script>
document.getElementById("changePage1").addEventListener("click", ()=>{
const state = {name: 'page1'};
history.pushState(state, '', 'page1')
});
document.getElementById("changePage2").addEventListener("click", ()=>{
const state = {name: 'page2'};
history.replaceState(state, '', 'page2')
});
window.onpopstate = (event)=>{
console.log('onpopstate', event.state, location.pathname);
}
</script>
Хотя URL-адрес можно изменить с помощью pushState и replaceState, он не будет активно запускать перезагрузку браузера.pushState、replaceStateРазница в том,history.pushState()новая запись в истории;history.replaceState()заключается в изменении (замене) текущей записи истории.
См. следующий пример: из history.html выполните команду pushState(), чтобы добавить в историю страницу 1, затем используйте команду replaceState(), чтобы заменить страницу 2 на страницу 1. На этот раз нажмите на браузер返回Кнопку можно найти, вернувшись сразу на страницу history.html, а не возвращаясь на страницу page1. Как можно заметитьhistory.replaceState()Роль замены истории.
window.onpopstateСлушатели событий — это прямые и обратные события браузера.
При обновлении страницы в режиме истории она запросит у сервера новый ресурс «127.0.0.1:5500/page1». Если серверная часть не выполняет соответствующую обработку, браузер сообщит об ошибке 404. Сотрудничество с серверной частью требуется для поиска страницы, которая не может быть найдена, по html-адресу ресурса проекта, например index.html. В то же время контент, отображаемый на странице 404, контролируется интерфейсной маршрутизацией.
developer.Mozilla.org/this-cn/docs/…
Параметры динамического пути
Способ 1: параметры
Нам часто нужно сопоставить все маршруты, соответствующие определенному шаблону, с одним и тем же компонентом. Например, у нас есть компонент User, который используется для отображения всех пользователей с разными идентификаторами. Затем мы можем использовать «динамический сегмент» в пути маршрутизации vue-router для достижения этого эффекта:
const User = {
template: '<div>User</div>'
}
const router = new VueRouter({
routes: [
//动态路径参数 以冒号开头
{ path: 'user/:id', name: 'user', component: User}
]
})
Теперь такие вещи, как /user/foo и /user/bar, будут сопоставляться с одним и тем же маршрутом.
Двоеточие «аргумент пути»: тег. При совпадении с маршрутом значение параметра будет установлено в $ Route.params, его можно использовать внутри каждой сборки. Таким образом, мы можем обновить шаблоны пользователей, вывести ID текущего пользователя:
const User = {
template: '<div>{{ $route.params.id }}</div>'
}
использовать:
this.$router.push({name: 'user', params: {id: "zs"}});
http://localhost:8080/#/user/zsАргументы появляются в пути
Способ 2: запрос
this.$router.push({name: 'list', query: {name: 'William'}})
использовать
<div>List:{{$route.query.name}}</div>
http://localhost:8080/#/list?name=Williamпараметры будут начинаться с?a=bотображать в виде
Отложенная загрузка маршрута
в основном используютimport()реализация функции.
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: ()=>import(/* webpackChunkName: "User"*/'./components/User.vue') }
]
})
$маршрутизатор и $маршрут
- $router относится ко всему объекту маршрута; вы можете использовать
this.$router.push({name: 'user'})Перейти на страницу перехода. - $route относится к объекту маршрута текущей страницы; вы можете использовать
this.$route.params.idилиthis.$route.query.idПолучить параметры, переданные текущим объектом маршрутизации
навигационная охрана
Глобальная передняя защита
const router = new VueRouter({...});
router.beforeEach((to, from, next)=>{
//...
})
- to: Объект маршрута, целевой объект маршрута, который необходимо ввести
- from: объект маршрута, маршрут, который собирается покинуть текущая навигация
- следующий: Функциональная функция, функция для продолжения выполнения.
- Далее (); продолжать выполнение
- next({ path: '/'}); Перейти к указанному адресу маршрутизации
TypeScript
Особенности TypeScript
-
Проверка типов. TypeScript выполняет строгую статическую проверку типов при компиляции кода. Это означает, что потенциальные подводные камни на этапе кодирования не нужно выводить в онлайн.
-
языковое расширение. TypeScript будет включать функции из ES6 и будущих предложений, таких как асинхронные операции и декораторы. Некоторые функции также заимствованы из других языков, например, интерфейсы и абстрактные классы.
-
Свойства инструмента. TypeScript может быть скомпилирован в стандартный Javascript. Работает в любом браузере и операционной системе. Без каких-либо накладных расходов во время выполнения. С этой точки зрения TypeScript больше похож на инструмент.
Типы
Boolean Boolean, Number, String String, Array Array, Type, Enumeration, Interface, ANY, VOID и т. д.
- кортеж. Кортеж представляет собой массив с известным количеством и типом элементов, и каждый элемент не обязательно должен быть одного типа.
let x: [string, number, boolean] = ['hello', 100, true];
- интерфейс. interface для определения интерфейса, интерфейс можно понимать как описание типа данных. Например, мы определяем параметр, который должен быть принят методом, и какие свойства или методы должен иметь этот параметр. В это время вы можете использовать интерфейс для определения параметров метода.
interface params{
search: string;
page?: number;
size?: number;
}
function foo(p: params): string{}
- Дженерики. Обобщения гарантируют недетерминированность и непротиворечивость типов. Например, в функции, чтобы гарантировать, что тип возвращаемого значения функции соответствует типу входной переменной, мы можем использовать дженерики.
Разница между типом закуски и интерфейсом:
- Тип может объявлять псевдонимы примитивных типов, типов объединения и кортежей, но интерфейс не может.
- В типовом операторе вы можете использовать тип для получения экземпляра типа
- Тип поддерживает тип отображения типа, интерфейс не
- интерфейс может объявить слияние, тип не может
woo woo woo.cn blog on.com/Meng couple/afraid/12…
Модули и пространства имен
-
Использование модулей в TypeScript соответствует модулям ES6. Используйте синтаксис экспорта для экспорта переменных и методов модулей; используйте импорт для импорта переменных и методов других модулей.
-
Пространства имен. Пространства имен реализуются в TypeScript с помощью ключевого слова namespace. Например, переменные в пространстве имен Shape доступны только в этом пространстве имен.Если вы хотите получить глобальный доступ к переменным и методам, вам нужно экспортировать их с помощью ключевого слова export.
-
Пространство имен может быть разделено на несколько файлов.
-
Наконец, пространство имен компилируется в глобальную переменную и немедленно выполняющуюся функцию.
Наконец, пространства имен не следует смешивать с модулями, а использование пространств имен лучше всего использовать в глобальной среде.
Файл декларации
Если мы хотим использовать сторонние библиотеки классов, такие как jQuery, lodash и т. д., в TypeScript, нам необходимо предоставить файлы объявлений этих библиотек классов (оканчивающиеся на .d.ts), чтобы предоставить доступ к API. Как правило, после установки пакета объявления типов сторонней библиотеки классов мы можем использовать его в TypeScript. Возьмите jQuery в качестве примера:
npm install -D jquery @types/jquery
Процесс составления ТС
Подобно Babel и другим инструментам, которые компилируются в Javascript, процесс компиляции TS состоит из следующих трех шагов:
Анализ -> Преобразование -> Генерация
Содержит следующие основные части:
- Сканер: генерировать токен из исходного кода
- Парсер: создание AST из токена
- Связующее: создание символа из AST
- Checker: проверка типов
- Emitter: создайте окончательный файл JS
цитируется:nuggets.capable/post/684490…
Подробнее о TypeScript:nuggets.capable/post/690313…
благодарный
Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам это нравится или у вас есть вдохновение, пожалуйста, поставьте лайк, это также поощрение автора.