За последние несколько дней я постепенно узнал оvue-следующий (Vue 3.0)некоторые из новых функций, особенно новыеComposition APIПрименение. Самая важная и основная часть этого нового API, вероятно, реализует адаптивные функции. Более того, этот адаптивный API можно использовать не только вvue-nextЕго также можно использовать независимо в окружающей среде.
Когда я читаю исходный код, я вижу,vue-nextвсе поTypeScriptБилд, похоже тс должен выучить навыки. Далее дайте знатьvue-next.
vue-nextОсновные архитектурные улучшения и новые функции запланированы и реализованы:
- Используйте модульную архитектуру
- Оптимизировать «Дерево блоков»
- Более агрессивная функция подъема статического дерева
- Поддержка исходной карты
- Встроенный префикс идентификатора (также известный как «stripWith»)
- Встроенная функция красивой печати
- С удаленными функциями исходной карты и префикса идентификатора версия браузера, сжатая с помощью Brotli, уменьшается примерно на10KB
Обновление среды выполнения (Runtime) в основном отражается в следующих аспектах:
- Значительное увеличение скорости
- Поддерживает как Composition API, так и Options API, а также типизацию
- Обнаружение изменений данных на основе прокси
- Поддержка фрагментов
- Порталы поддержки
- Поддержка приостановки с асинхронной настройкой ()
Наконец, есть некоторые функции 2.x, которые не были перенесены, а именно:
- SFC compiler
- Рендеринг на стороне сервера (SSR рендеринга на стороне сервера)
==IE11 в настоящее время не поддерживается==
vue-следующий (Vue 3.0)Хотя исходный код был выпущен, ожидается, что официальная версия 3.0 не будет выпущена до первого квартала 2020 года.
Анатомия каталога
В репозитории кода есть каталог пакетов, который в основном содержитvue-nextСоответствующая реализация функции исходного кода, конкретное содержание выглядит следующим образом.
├── packages
│ ├── compiler-core # 所有平台的编译器
│ ├── compiler-dom # 针对浏览器而写的编译器
│ ├── reactivity # 数据响应式系统
│ ├── runtime-core # 虚拟 DOM 渲染器 ,Vue 组件和 Vue 的各种API
│ ├── runtime-dom # 针对浏览器的 runtime。其功能包括处理原生 DOM API、DOM 事件和 DOM 属性等。
│ ├── runtime-test # 专门为测试写的runtime
│ ├── server-renderer # 用于SSR
│ ├── shared # 帮助方法
│ ├── template-explorer
│ └── vue # 构建vue runtime + compiler
-
ядро компилятора: независимый от платформы компилятор, который включает как расширяемую базовую функциональность, так и все независимые от платформы плагины. Предоставляет API, связанные с AST и baseCompile, которые могут преобразовать строку в AST.
-
компилятор-дом: основанный на ядре компилятора компилятор для браузеров инкапсулирован
-
runtime-core: независимая от платформы среда выполнения. Поддерживаемые функции включают в себя виртуальный рендерер DOM, компоненты Vue и различные API-интерфейсы Vue, которые можно использовать для настройки рендерера, а также в vue2.
-
runtime-dom: среда выполнения для браузера. Его функции включают обработку собственного API DOM, событий DOM и свойств DOM и т. д., а также предоставляют важные методы рендеринга и createApp.
const { render, createApp } = createRenderer<Node, Element>({ patchProp, ...nodeOps }) export { render, createApp } -
runtime-test: облегченная среда выполнения, написанная специально для тестирования. Например, метод renderToString открыт для внешнего мира, и я чувствую, что он все больше и больше похож на реакцию.
-
server-renderer: для SSR еще не реализован.
-
общий: не предоставляет никакого API, в основном содержит некоторые независимые от платформы внутренние вспомогательные методы.
-
vue: «полная» версия со ссылкой на упомянутые выше каталоги среды выполнения и компилятора. Код входного файла выглядит следующим образом
'use strict' if (process.env.NODE_ENV === 'production') { module.exports = require('./dist/vue.cjs.prod.js') } else { module.exports = require('./dist/vue.cjs.js') }Поэтому, если вы хотите прочитать исходный код, вам все равно нужно посмотреть на процесс сборки, который также соответствует vue2.
Обзор механизма адаптивного принципа Vue2.0 — defineProperty
Об этом принципе часто говорят, то есть о перехвате объектов и добавлении свойств к объектамsetа такжеgetметод, потому что ядроdefinePropertyТак что вам также нужно перехватить метод массива
объект перехвата
function observer(target){
// 如果不是对象数据类型直接返回即可
if(typeof target !== 'object'){
return target
}
// 重新定义key
for(let key in target){
defineReactive(target,key,target[key])
}
}
function update(){
console.log('update view')
}
function defineReactive(obj,key,value){
observer(value); // 有可能对象类型是多层,递归劫持
Object.defineProperty(obj,key,{
get(){
// 在get 方法中收集依赖
return value
},
set(newVal){
if(newVal !== value){
observer(value);
update(); // 在set方法中触发更新
}
}
})
}
const obj = {name:'zhuanzhuan'}
observer(obj);
obj.name = 'new-name';
输出:
update view
Перехват метода массива
const oldProtoMehtods = Array.prototype
const proto = Object.create(oldProtoMehtods)
function update(){
console.log('update view')
}
function defineReactive(obj,key,value){
observer(value) // 有可能对象类型是多层,递归劫持
Object.defineProperty(obj,key,{
get(){
// 在get 方法中收集依赖
return value
},
set(newVal){
if(newVal !== value){
observer(value)
update() // 在set方法中触发更新
}
}
})
}
['push','pop','shift','unshift'].forEach(method=>{
Object.defineProperty(proto, method,{
get(){
update()
return oldProtoMehtods[method]
}
})
})
function observer(target){
if(typeof target !== 'object'){
return target
}
// 如果不是对象数据类型直接返回即可
if(Array.isArray(target)){
Object.setPrototypeOf(target, proto)
// 给数组中的每一项进行observr
for(let i = 0 ; i < target.length; i++){
observer(target[i])
}
return
}
// 重新定义key
for(let key in target){
defineReactive(target, key, target[key])
}
}
let obj = {hobby:[{name:'zhuanzhuan'}]}
observer(obj)
// 使用['push','pop','shift','unshift'] 方法,更改数组会触发视图更新
obj.hobby.push('转转')
// 更改数组中的对象也会触发视图更新
obj.hobby[0].name = 'new-name'
console.log(obj.hobby)
输出:
update view
update view
[ { name: [Getter/Setter] }, '转转' ]
Недостатки Object.defineProperty:
- Невозможно отслеживать изменения в массиве
- Требует глубокого обхода и тратит память
vue-next предварительные
Читаете ли вы эту статью или читаетеvue-nextИсходный код адаптивного модуля, в первую очередь, необходимы два очка знаний:
- Proxy: Объекты используются для определения пользовательского поведения для основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.). Новый встроенный служебный класс прокси в ES6.
- Reflect: это встроенный объект, предоставляющий методы для перехвата операций JavaScript. Эти методы такие же, как у обработчиков прокси. Reflect не является функциональным объектом, поэтому его нельзя построить. Новые служебные классы отражения в ES6
Proxy
let data = [1,2,3]
let p = new Proxy(data, {
get(target, key) {
console.log('获取值:', key)
return target[key]
},
set(target, key, value) {
console.log('修改值:', key, value)
target[key] = value
return true
}
})
p.push(4)
输出:
获取值: push
获取值: length
修改值: 3 4
修改值: length 4
СравниватьdefinepropertyОтличным моментом является то, что и массивы, и объекты могут запускаться напрямую.getterа такжеsetter, но массив срабатывает дважды, потому что получениеpushи изменитьlengthтакже срабатывает, когда
Помимо более высокой производительности, Proxy заменяет deineProperty и имеет следующие недостатки, из-за чегоПричина удаления:
- Добавление или удаление атрибутов также не может быть отслежено;
- Добавление и удаление элементов массива также нельзя контролировать
Reflect
let data = [1,2,3]
let p = new Proxy(data, {
get(target, key) {
console.log('获取值:', key)
return Reflect.get(target,key)
},
set(target, key, value) {
console.log('修改值:', key, value)
return Reflect.set(target,key, value)
}
})
p.push(4)
输出:
获取值: push
获取值: length
修改值: 3 4
修改值: length 4
Множественные триггеры и глубоко вложенные проблемы
let data = {name:{ title:'zhuanzhuan'}}
let p = new Proxy(data, {
get(target, key) {
console.log('获取值:', key)
return Reflect.get(target,key)
},
set(target, key, value) {
console.log('修改值:', key, value)
return Reflect.set(target,key, value)
}
})
p.name.title = 'xx'
输出:
获取值: name
я покажу тебе позжеvue-nextКак это решается.
Инициализировать проект
Проект зависимостей vue.global.js [рекомендуется]
-
клонировать проект
$ git clone https://github.com/vuejs/vue-next.git -
редактировать файл
$ npm run dev -
копировать файл
После запуска вышеуказанной команды он сгенерирует
[项目根路径]/packages/vue/dist/vue.global.jsдокумент
Зависит от @vue/composition-api
-
Установить vue-кли
$ npm install -g @vue/cli # OR $ yarn global add @vue/cli -
Создать проект
$ vue create my-project # OR $ vue ui -
Установить в проект
composition-apiопытvue-nextновые особенности$ npm install @vue/composition-api --save # OR $ yarn add @vue/composition-api -
используя любой
@vue/composition-apiПрежде чем предлагать компетенцию, вы должны сначала пройтиVue.use()установитьimport Vue from 'vue' import VueCompositionApi from '@vue/composition-api' Vue.use(VueCompositionApi)После установки плагина вы можете использовать новыйComposition APIдля разработки компонентов.
vue-следующие ранние последователи
Просто скопируйте приведенный ниже код и запустите его, чтобы увидеть эффект. Рекомендуется использовать старшую версию браузера Chrome, не забудьте открыть инструмент отладки F12!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://s1.zhuanstatic.com/common/js/vue-next-3.0.0-alpha.0.js"></script>
</head>
<body>
<div id='app'></div>
</body>
<script>
const { createApp, reactive, computed, effect } = Vue;
const RootComponent = {
template: `
<button @click="increment">
{{ state.name }}今年{{state.age}}岁了,乘以2是{{state.double}}
</button>
`,
setup() {
const state = reactive({
name: '转转',
age: 3,
double: computed(() => state.age * 2)
})
effect(() => {
console.log(`effect 触发了! - ${state.name}今年${state.age}岁了,乘以2是${state.double}`)
})
function increment() {
state.age++
}
return {
state,
increment
}
}
}
createApp().mount(RootComponent, '#app')
</script>
</html>
этоreactiveЭто все больше похоже на react-хуки, каждый может перейти наComposition API RFCПодробнее см. здесь.
-
templateтак же, как раньшеvue-nextРукописный ввод также поддерживаетсяrenderнаписание,templateа такжеrenderВ случае одновременного существования приоритет отдаетсяrender. -
setupВарианты — это новые крупные изменения, как следует из названия,setupФункция будет выполнена до того, как компонент будет смонтирован (beforeCreateа такжеcreatedВ течение жизненного цикла) запускается один раз, аналогично роли инициализации компонента,setupНужно вернуть объект или функцию. Возвращенный объект будет назначен экземпляру компонента.renderContext, к которому можно получить доступ в области шаблона компонента, напримерdataВозвращаемое значение. Возвращающие функции рассматриваются как компонентыrender. Подробности смотрите в документации. -
reactiveРоль объекта состоит в том, чтобы обернуть объект в отзывчивый объект, черезProxyПроксируемый объект. -
Пример счетчика выше, в компоненте
setupВ функции создается реактивный объектstateсодержитageАтрибуты. затем создалincrementУвеличивающая функция, наконецstateа такжеincrementвернуться к прицелу, вот такtemplateвнутреннийbuttonкнопка для доступаincrementФункция связана с обратным вызовом клики,age.我们点击按钮,按钮上的数值就能跟着递增。
Ссылаться на
- Быстро продвинутый Vue3.0:сегмент fault.com/ah/119000002…
- RFC API на основе функций Vue:zhuanlan.zhihu.com/p/68477600
Я считаю, что у каждого естьvue-следующий (Vue 3.0)Иметь предварительное понимание и успешно запустить код раннего внедрения.
Следующая главаvue-next(Vue 3.0)之 小试牛刀продолжать вести вас к мастеруvue-nextФункциональный API.