Vue основная архитектура и его применение

Vue.js

Время чтения составляет около 16 ~ 22 мин.
Автор: Ван Ван
Домашняя страница:Woohoo. Calling.com/people/wang…

Введение

На рынке существует множество оптимизированных фреймворков с открытым исходным кодом, основанных на ядре и компиляции vue, которые представляют возможности Vue для не-веб-сценариев, поэтому стоимость обучения невелика, и это приветствуется большинством разработчиков.Ниже приведен общий список. того, что я узнал Лучше приветствую всех, кто комментирует

Классификация Технология
кроссплатформенный родной weex
Апплеты mpvue
рендеринг на стороне сервера Vue SSR
Небольшая программа многотерминальная унифицированная структура uni-app

Существует бесчисленное множество фреймворков, которые обеспечивают опыт разработки, подобный Vue, например, фреймворк апплета --wepy,

С других аспектов, Vue имеет более 100 звезд каждый день в ежедневном списке github, что показывает его популярность, поэтому все изо всех сил стараются обеспечить поддержку Vue в не-веб-областях. Тогда базовая архитектура Vue и ее приложение особенно важны.

2. Базовая архитектура Vue

Понимание базовой архитектуры Vue является основной предпосылкой для предоставления возможностей Vue для не-веб-полей. Ядро Vue разделено на три части: ядро, компилятор и платформа.Ниже описаны его принципы и возможности.

1. ядро

ядро - это душа Vue. Это ядро, которое рекурсивно генерирует указанное представление платформы через vnode и автоматически обновляет представление при изменении данных. Также из-за механизма VNode ядро ​​​​независимо от платформы, даже если функция ядра в рендеринге пользовательского интерфейса.

Я объясню суть из следующих аспектов

  • устанавливать
  • инструкция
  • Вноде---- фокус
  • Экземпляр компонента vm и взаимосвязь между vm
  • nextTick
  • Наблюдатель ---- фокус
  • Алгоритм сравнения vnode ---- фокус
  • coreСводка

1.1 Крепление

Добавляйте определенные элементы платформы, сгенерированные vnode, к известным узлам. Возьмем в качестве примера веб-платформу, используем vnode для создания dom с помощью document.createElement, а затем присоединим его к узлу в дереве документов. Позже мы часто будем говорить о монтировании компонентов, что означает, что исполнительный компонент генерирует vnode, соответствующий рендерингу, а затем проходит vnode для генерации определенных элементов платформы.Элемент корневого узла компонента будет присоединен к родительскому элементу.

1.2 Инструкции

Инструкции — это атрибуты с определенным значением в Vue.Инструкции делятся на две категории.Одна — обработка во время компиляции, которая отражается в сгенерированной функции рендеринга, например: v-if, v-for, другая используется во время выполнения, и многое другое. Большинство из них представляют собой операции над сгенерированными конкретными элементами платформы, а в случае веб-платформ — операции над DOM.

1.3 VNode--------- фокус

vnode — это виртуальный узел, который представляет собой дальнейшую абстракцию (упрощенную версию) конкретного объекта элемента платформы.Каждый элемент платформы соответствует vnode, и структура конкретного элемента платформы может быть полностью восстановлена ​​через структуру vnode. vnode объясняется ниже с точки зрения веб-платформы. Для Интернета предположим следующую структуру:

<div class="box" @click="onClick">------------------对应一个vnode
    <p class="content">哈哈</p>-------对应一个vnode
    <TestComps></TestComps>----------自定义组件同样对应一个vnode
    <div></div>-----------------------对应一个vnode
</div>

После того, как модуль компиляции Vue сгенерирует функцию рендеринга, выполнение этой функции рендеринга сгенерирует соответствующую структуру vnode:

//这里我只列出关键的vnode信息
{
  tag:'div',
  data:{attr:{},staticClass:'box',on:{click:onClick}},
  children:[{
    tag:'p',
    data:{attr:{},staticClass:'content',on:{}},
    children:[{
      tag:'',
      data:{},
      text:'哈哈'
    }]
  },{
    tag:'div',
    data:{attr:{},on:{}},
  },{
    tag:'TestComps',
    data:{
        attr:{},
        hook:{
            init:fn,           
            prepatch:fn,
            insert:fn,
           destroy:fn
        }
     },
  }]  
}

Самый внешний div соответствует vnode, который содержит три дочерних vnode.Обратите внимание, что пользовательский компонент также соответствует vnode, но экземпляр компонента висит на этом vnode.

1.4 Связь между экземпляром компонента vm и vm --------- фокус

Экземпляры компонентов на самом деле являются объектами экземпляров Vue. Они есть только у пользовательских компонентов, но нет элементов, связанных с платформой. Чтобы понять суть Vue, важно понять следующую взаимосвязь. Теперь давайте почувствуем это:

Предполагая, что существует шаблон со следующей структурой, vnode элемента представляет соответствующее сгенерированное имя vnode:

// new Vue的template,对应的实例记为vm1
<div vnode1>
  <p vnode2></p>
  <TestComps vnode3
             testAttr="hahha"
             @click="clicked"
             :username="username"
             :password="password"></TestComps>
</div>
// TestComps的template,对应的实例记为vm2
<div vnode4>
  <span vnode5></span>
  <p vnode6></p>
</div>
// 生成的vnode关系树为
vnode1={
  tag:'div',
  children:[vnode2,vnode3]
}
vnode3={
  tag:'TestComps',
  children:undefined,
  parent:undefined
}
vnode4={
  tag:'div',
  children:[vnode5,vnode6],
  parent:vnode3             //这一点关系很重要
}
// 生成的vm关系树为
vm1={
  $data:{password: "123456",username: "aliarmo"}, //组件对应state
  $props:{} //使用组件时候传下来到模板里面的数据
  $attrs:{},
  $children:[vm2],             
  $listeners:{}
  $options: {
    components: {}
    parent: undefined   //父组件实例
    propsData: undefined    //使用组件时候传下来到模板里面的数据
    _parentVnode: undefined 
  }
  $parent:undefiend               //当前组件的父组件实例
  $refs:{}                 //当前组件里面包含的dom引用
  $root:vm1                 //根组件实例
  $vnode:undefined                 //组件被引用时候的那个vnode,比如<TestComps></TestComps>
  _vnode:vnode1       //当前组件模板根元素所对应的vnode对象
}

vm2={
  $data:{} //组件对应state
	$props:{password: "123456",username: "aliarmo"} //使用组件时候传下来到模板里面的数据
  $attrs:{testAttr:'hahha'},
  $children:[],             
  $listeners:{click:fn}
  $options: {
    components: {}
    parent: vm1   //父组件实例
    propsData: {password: "123456",username: "aliarmo"}    //使用组件时候传下来到模板里面的数据
    _parentVnode: vnode3 
  }
  $parent:vm1               //当前组件的父组件实例
  $refs:{}                 //当前组件里面包含的dom引用
  $root:vm1                 //根组件实例
  $vnode:vnode3                 //组件被引用时候的那个vnode,比如<TestComps></TestComps>
  _vnode:vnode4       //当前组件模板根元素所对应的vnode对象
}

1.5 nextTick

Это позволяет нам делать некоторые операции в следующем цикле событий, а не в этом цикле, для асинхронных обновлений принцип заключается в микрозадаче и макрозадаче

Давайте посмотрим на кусок кода:

new Promise(resolve=>{
  return 123
}).then(data=>{
  console.log('step2',data)
})
console.log('step1')

В результате сначала выводится шаг 1, а затем шаг 2, обещание разрешения — это микрозадача, а код синхронизации — макрозадача.

// 在Vue中
this.username='aliarmo' // 可以触发更新
this.pwd='123'          // 同样可以触发更新

Если два состояния изменяются одновременно, вызовет ли это два обновления? Нет, потому что обратный вызов, инициированный this.username для запуска обновления, будет помещен в микрозадачу, реализованную Promise или MessageChannel, или в макрозадачу, реализованную setTimeout, в короткое замыкание на следующий цикл событий.

1.6 Наблюдатель --------- фокус

Компонент соответствует наблюдателю. Этот наблюдатель создается при монтировании компонента. Состояние компонента, включая данные и свойства, являются наблюдателями. Любые изменения в наблюдателе будут уведомлены наблюдателю, а изменения в наблюдателе будут Причина Действие, выполняемое наблюдателем,vm._update(vm._render(), hydrating), компонент выполняет повторный рендеринг для создания vnode и patch.

Важно понять эту связь: Наблюдатель содержит определение реакции на изменения. Компонент соответствует наблюдателю, соответствующему всем наблюдателям в компоненте. Наблюдатель может использоваться для других компонентов, тогда наблюдатель будет соответствовать нескольким наблюдателям. Когда наблюдатель изменяется, все наблюдатели уведомляются о необходимости отреагировать на обновление.

Состояние1 компонента А изменяется, что приводит к тому, что наблюдатель, наблюдающий за этим состоянием1, получает уведомление об изменении, что приводит к повторному рендерингу компонента А для создания нового vnode.Во время процесса исправления нового vnode и старого vnode компонента A, он будет updateChildrenComponent, то есть реквизиты подкомпонента B сбрасываются до нового значения, потому что подкомпонент B наблюдает за входящим состоянием1, поэтому он уведомит соответствующий наблюдатель, что приведет к обновлению подкомпонента B

Процесс создания всей системы наблюдения:

  1. При создании экземпляра компонента он будет наблюдать за данными и реквизитами,
  2. Выполните неглубокий обход входящих реквизитов и сбросьте дескрипторы свойства get и set свойства.Если значением свойства реквизита является объект, то объект глубоко наблюдается в родительском компоненте, поэтому реквизит представляет собой неглубокий обход
  3. Наблюдатель будет глубоко просматривать данные, переопределять атрибуты, содержащиеся в данных, то есть defineReactive, и сбрасывать получение и установку дескриптора атрибута.
  4. Когда компонент смонтирован, это будет новый Wacther, текущим экземпляром наблюдателя будет pushTarget, установленный в качестве целевого наблюдателя, а затем выполненныйvm._update(vm._render(), hydrating), выполнение функции рендеринга вызывает вызов функции получения атрибута. Каждый атрибут будет соответствовать экземпляру dep. В это время экземпляр dep связан с наблюдателем, соответствующим компоненту для реализации сбора зависимостей, и popTarget после объединения.
  5. Если есть подкомпоненты, это приведет к созданию экземпляров подкомпонентов, повторите вышеуказанные шаги.

процесс ответа на изменение состояния:

  1. Когда состояние изменится, вызовите функцию set дескриптора свойства, и dep уведомит связанный наблюдатель о переходе к задаче nextTick. Функция запуска этого экземпляра наблюдателя содержитvm._update(vm._render(), hydrating), Выполните эту функцию запуска, вызывая регенерацию vnode, исправление и изменение для достижения цели обновления пользовательского интерфейса.

Как изменение состояния родительского компонента приводит к изменению дочернего компонента?

После того, как состояние родительского компонента будет обновлено, функция рендеринга будет повторно выполнена для создания нового vnode.В процессе патча oldVnode и newVnode, если встречается vnode компонента, он будет updateChildrenComponent.Операция здесь заключается в обновлении props дочернего компонента.Поскольку подкомпоненты отслеживают изменения свойства props, подкомпоненты перерисовываются

Родительский компонент передает объект дочернему компоненту, а дочерний компонент изменяет реквизиты входящего объекта.Как обновляется родительский компонент?

Основная предпосылка: если в свойствах есть объект, переданный родительским компонентом дочернему компоненту, то дочерний компонент получает ссылку на этот объект. То есть this.person в ParentComps и this.person в SubComps указывают на один и тот же объект.

// 假定父组件传person对象给子组件SubComps
Vue.component('ParentComps',{
  data(){
    return {
      person:{
        username:'aliarmo',
        pwd:123
      }
    }
  },
  template:`
    <div>
      <p>{{person.username}}</p>
      <SubComps :person="person" />
    </div>
  `
})

Теперь мы находимся в SubComps, обновим свойство объекта person, например: this.person.username='wmy' Это приведет к обновлению ParentComps и SubComps, почему?

Поскольку Vue будет глубоко рекурсивно наблюдать за каждым свойством объекта в ParentComps, когда рендеринг ParentComps выполняется в первый раз, привязать Watcher ParentComps, и после передачи его в SubComps он не будет наблюдать входящий объект. of SubComps выполняется в первый раз, он будет привязан к Watcher of SubComps, поэтому, когда SubComps изменит значение this.person.username, он уведомит двух Watchers, что приведет к обновлению. Это хорошее объяснение того факта, что монтирование новых свойств входящего объекта свойства реквизита не запускает рендеринг, поскольку объект свойств входящего реквизита наблюдается в родительском компоненте.

1.7 Алгоритм сравнения vnode --------- фокус

Когда состояние компонента изменится, повторно выполните функцию рендеринга, чтобы сгенерировать новый vnode, а затем сравните вновь сгенерированный vnode со старым vnode, чтобы обновить исходное представление с минимальными затратами.Принцип алгоритма diff состоит в том, чтобы генерировать структуру, соответствующую newChildrenVnodes, путем перемещения, добавления, удаления и замены структуры, соответствующей oldChildrenVnodes, причем каждый старый элемент можно повторно использовать только один раз, а конечное положение старого элемента зависит от текущего новый внод. Необходимо явно передавать в алгоритм diff дочерние узлы двух одинаковых Vnodes, с начала и конца двух, и перемещаться к середине одновременно, пока один из двух не достигнет середины.

PS: oldChildrenVnodes представляет собой старый набор дочерних узлов vnode, newChildrenVnodes представляет новый набор дочерних узлов vnode, сгенерированный после изменения состояния.

Прежде чем говорить об этом алгоритме, мы должны сначала понять, как судить о двух vnodes как о одинаковых Vnodes, я только перечислю их в общих чертах:

  1. Ключевые значения vnodes равны, например<Comps1 key="key1" />, <Comps2 key="key2" />, значения ключей не равны,<Comps1 key="key1" />, <Comps2 key="key1" />, значение ключа равно,<div></div>,<p></p>, Значение ключа этих двух не определено, а значение ключа равно.Это основная предпосылка sameVnode.
  2. Теги vnodes одинаковые, все они комментарии или не комментарии, а данные определены или не определены одновременно.Если тег входной, то тип должен быть одинаковым.Есть и другие условия, которые не очень важны к нам и не будут перечислены.

Весь процесс сравнения vnode

Основная предпосылка заключается в том, что для понимания этого различия vnode вы должны сначала понять, что такое vnode, как его сгенерировать, а также взаимосвязь между vnode и elm.Подробности см. в концепции vnode выше.

  1. Если оба vnode одинаковые Vnode, исправьте vnode
  2. патч vnode процесс

  (1) Во-первых, вяз vnode указывает на вяз oldVnode

  (2) Используйте данные vnode для обновления атрибута elm, класса, стиля, domProps, событий и т. д.

  (3) Если vnode является текстовым узлом, непосредственно установите текст elm, end

  (4) Если vnode является нетекстовым узлом && имеет дочерние элементы && oldVnode не имеет дочерних элементов, то elm добавляется напрямую

  (5) Если vnode является нетекстовым узлом && не имеет дочерних элементов && oldVnode имеет дочерние узлы, то непосредственно удалить дочерний узел elm

  (6) Если нетекстовый узел && имеет дочерние узлы, updateChildren, введите алгоритм сравнения,Первые 5 шагов исключают ситуацию, когда diff не может быть выполнен

  1. алгоритм diff, здесь мы берем веб-платформу в качестве примера

Здесь также подчеркивается, что дочерние узлы двух одинаковых Vnodes передаются в алгоритм сравнения., то как заменить oldChildrenVnodes на newChildrenVnodes, проще всего пройтись по newChildrenVnodes и напрямую регенерировать этот html фрагмент, все довольны. Но при этом будет постоянно создаваться элемент, который влияет на производительность, поэтому предшественники придумали этот алгоритм сравнения.

(1) Возьмите самый левый узел из двух, чтобы определить, является ли он одним и тем же Vnode, и если да, выполните вышеуказанное.Второй этап исправления процесса vnode, После завершения всего процесса в это время были обновлены класс, стиль, события и т. д. elm, а дочерняя структура elm также была обновлена ​​​​через весь процесс, упомянутый выше.В настоящее время это зависит от нужно ли перемещать вяз, т.к. все Крайний левый узел дочерний, поэтому позиция не меняется, а положение самого левого узла смещается вперед на один шаг

(2) Если это не случай, описанный в (1), возьмите крайний правый узел из двух, который аналогичен процессу оценки (1), но положение самого правого узла перемещается на один шаг вперед.

(3) Если это не случай, описанный в (1) (2), возьмите самый левый узел из oldChildrenVnodes и самый правый узел из newChildrenVnodes, что аналогично процессу оценки (1), но,Позиция вяза должна быть перемещена вправо от вяза в крайнем правом углу oldVnode., так как vnode берет самый правый узел, если самый правый узел oldVnode является тем же самым Vnode, положение не нужно менять, поэтому положение самого правого узла newChildrenVnodes и самого правого узла oldChildrenVnodes соответствует, но поскольку он повторно используется Крайний левый узел oldChildrenVnodes и крайний правый узел oldChildrenVnodes не использовались повторно, поэтому их нельзя заменить, поэтому переместитесь вправо от крайнего правого вяза oldChildrenVnodes. Затем позиция самого левого узла oldChildrenVnodes перемещается на один шаг вперед, а позиция самого правого узла newChildrenVnodes перемещается на один шаг вперед.

(4) Если это не случай, описанный в (1) (2) (3), возьмите самый правый узел из oldChildrenVnodes и самый левый узел из newChildrenVnodes, что аналогично процессу оценки (1), но,Позиция вяза должна быть перемещена левее самого левого вяза из oldChildrenVnodes., поскольку vnode берет самый левый узел, если крайний левый узел oldChildrenVnodes является тем же самым Vnode, положение не нужно менять, поэтому крайний левый узел newChildrenVnodes и oldChildrenVnodes соответствует положению самого левого узла, но поскольку он повторно используется. крайний правый узел oldChildrenVnodes и крайний левый узел oldChildrenVnodes не использовались повторно, поэтому их нельзя заменить, поэтому переместите их слева от крайнего левого elm of oldChildrenVnodes. Затем позиция самого правого узла oldChildrenVnodes перемещается на один шаг вперед, а позиция самого левого узла newChildrenVnodes перемещается на один шаг вперед.

(5) Если это не случай, описанный в (1) (2) (3) (4), найдите oldVnode в oldChildrenVnodes, а крайний левый узел newChildrenVnodes — тот же Vnode, если он не найден, используйте этот новый vnode для создания новый элемент, позиция вставки описана позже.Если найдено, это то же самое, что и процесс оценки (1), ноПозиция вставки находится слева от крайнего левого узла oldChildrenVnodes., потому что если крайний левый узел newChildrenVnodes и крайний левый узел oldChildrenVnodes являются одинаковыми Vnode, положение не нужно менять, и повторно используется вяз oldVNode, найденный в oldChildrenVnodes. Повторно используемый oldVnode не будет извлекаться позже. Затем крайняя левая позиция узла newChildrenVnodes перемещается на один шаг вперед.

(6) После вышеуказанных шагов крайний левый узел oldChildrenVnodes или newChildrenVnodes совпадает с крайним правым узлом и выходит из цикла.

(7) Если крайний левый узел oldChildrenVnodes сначала совпадает с самым правым узлом, это означает, что newChildrenVNodes и узлы не были вставлены, рекурсивно создайте соответствующие элементы этих узлов, а затемВставить справа от самого левого узла oldChildrenVnodes или слева от самого правого узла, потому что он перемещается ближе к середине от начальной и конечной позиции двух.Подумайте об этом, если первый оставшийся узел newChildrenVNodes и крайний левый узел oldChildrenVnodes являются одним и тем жеVnode, положение не нужно менять.

(8) Если крайний левый узел newChildrenVnodes сначала совпадает с крайним правым узлом, это означает, что в oldChildrenVnodes есть участок структуры, который не использовался повторно, а начальная и конечная позиции близки к середине, поэтомуПозиция, которая не используется повторно, — это узел между крайним левым и крайним правым узлами oldChildrenVnodes., удалите вяз, соответствующий узлу.

Возьмите каштан, чтобы описать конкретный процесс сравнения (веб-платформа):

// 有Vue模板如下
<div>    ------ oldVnode1,newVnode1,element1
  <span v-if="isShow1"></span>  -------oldVnode2,newVnode2,element2
  <div :key="key"></div>  -------oldVnode3,newVnode3,element3
  <p></p>    -------oldVnode4,newVnode4,element4
  <div v-if="isShow2"></div>    -------oldVnode5,newVnode5,element5
</div>

// 如果 isShow1=true,isShow2=true,key="aliarmo"那么模板将会渲染成如下:
<div>
  <span></span>--------------element2
  <div key="aliarmo"></div>----------element3
  <p></p>-------------element4
  <div></div>----------element5
</div>

// 改变state,isShow1=false,isShow2=true,key="wmy",那么模板将会渲染成如下:
<div>
  <div key="wmy"></div>------------element6
  <p></p>-------------------element4
  <div></div>---------element5
</div>

Итак, как формируется структура DOM после изменения состояния?

Как показано выше, вisShow1=true,isShow2=true,key="aliarmo"Условно результирующая структура vnode имеет вид:oldVnode1,oldVnodeChildren=[oldVnode2,oldVnode3,oldVnode4,oldVnode5]

Соответствующая структура DOM:

изменить состояние наisShow1=false,isShow2=true,key="wmy"После этого результирующая новая структура vnode

newVnode1,newVnodeChildren=[newVnode3,newVnode4,newVnode5]

Сравнение двух старых и новых vnode слева, т.е.oldVnode2,newVnode3,нетsameVnode,

Сравнение двух новых и старых vnodes справа, т.е.oldVnode5,newVnode5,ДаsameVnode, без перемещения исходного местоположения Element5 исходная структура dom не изменилась,

Сравнение двух старых и новых vnode слева, т.е.oldVnode2,newVnode3,нетsameVnode,

Сравнение двух новых и старых vnodes справа, т.е.oldVnode4,newVnode4,ДаsameVnode, без перемещения исходного местоположения Element4 исходная структура dom не изменилась,

Сравнение двух старых и новых vnode слева, т.е.oldVnode2,newVnode3,нетsameVnode,

Сравнение двух новых и старых vnodes справа, т.е.oldVnode3,newVnode3, потому что значение ключа отличается, а неsameVnode,

Текущее крайнее левое и крайнее правое сравнение,oldVnode2,newVnode3,нетsameVnode

Текущее крайнее правое и крайнее левое сравнение,oldVnode5,newVnode3,нетsameVnode

Обходя oldVnodeChildren в поискахnewVnode3дляsameVnodeизoldVnode, если не найдено, используйтеnewVnode3создать новый элементElement6, вставленный в текущийoldVnode2Самый левый из соответствующего элемента, структура dom меняетсяnewVnodeChildrenДва конца перекрываются, выходят из цикла и удаляют оставшиеся немультиплексированные элементы.Element2,Element3

1.8 основное резюме

Теперь мы можем, наконец, стрижка, новое Vue () начало, ядро ​​внутри того, что произошло

  1. Новый Vue() или новый конструктор пользовательских компонентов (наследуется от VUE)
  2. Инициализировать, реквизиты, методы, вычислять, данные, смотреть, добавлять Observe в состояние и вызывать созданный жизненный цикл
  3. Начните монтировать компонент, убедитесь, что перед монтированием сгенерирована функция рендеринга.
  4. Новый наблюдатель, который приводит к рендерингу и исправлению. Обратите внимание, что наблюдатель соответствует компоненту. Реакция наблюдателя на изменения заключается в повторном выполнении рендеринга для создания vnode для исправления.
  5. Рендеринг выполняется в контексте текущего компонента (экземпляр компонента) для создания соответствующей структуры vnode.
  6. Если oldVnode отсутствует, исправление должно пройти по vnode в глубину, сгенерировать определенные элементы платформы, добавить атрибуты и события привязки к определенным элементам платформы, вызвать функцию ловушки, предоставленную пользовательской инструкцией, и добавить к существующему элементу. процесса, если встречается пользовательский компонент,шаг 1начать повторять
  7. Если есть oldVnode, то исправление использует алгоритм сравнения vnode для изменения исходного элемента платформы, и в качестве крайней меры создается новый элемент платформы.
  8. При изменении состояния уведомить наблюдателя, соответствующего компоненту, в котором находится состояние, и повторно выполнить рендеринг, чтобы сгенерировать vnode для исправления, то есть вернуться кШаг 4

2. компилятор

Компиляторная часть Vue отвечает за компиляцию шаблона, создание функций рендеринга и staticRender, а также однократную компиляцию для постоянного использования, поэтому обычно мы делаем это во время создания, чтобы улучшить производительность страницы. Выполните функции рендеринга и staticRender, чтобы сгенерировать виртуальные узлы, чтобы обеспечить этот уровень абстракции для ядра.

template ==》 AST ==》 递归ATS生成render和staticRender ==》VNode

(1) Процесс преобразования шаблона в AST

Давайте сначала интуитивно почувствуем AST, который описывает следующую структуру шаблона

// Vue模板

let template = `

 <div class="Test" :class="classObj" v-show="isShow">

 {{username}}:{{password}}

 <div>

 <span>hahhahahha</span>

 </div>

 <div v-if="isVisiable" @click="onClick"></div>
 <div v-for="item in items">{{item}}</div>


 </div>

 `

Ниже описан краткий процесс преобразования шаблона в AST:

  1. Если шаблон представляет собой строку, начинающуюся с

(1) Если это начальный тег, обработка аналогична следующей строке

<div class="Test" :class="classObj" v-show="isShow">

С помощью регулярных выражений теги и все списки атрибутов могут быть легко проанализированы, а затем списки атрибутов могут быть классифицированы, а v-if, v-for и другие инструкции, события, специальные атрибуты и т. д. могут быть проанализированы отдельно. разобранную часть и возвращается к шагу 1.

(2) Если это конечный тег, обработка аналогична следующей строке, тот же шаблон удаляет проанализированную часть и возвращается к шагу 1.

</div>
  1. Если это не первый случай, описание представляет собой строку, а обработка аналогична следующей строке интерполяции или обычному тексту, тот же шаблон удаляет проанализированную часть и возвращается к шагу 1.
{{username}}:{{password}} 或者 用户名:密码
  1. Если шаблон пуст, парсинг завершается

(2) AST генерирует рендеринг и staticRender

В основном обход AST (заинтересованные студенты могут испытать это на себе, например: обход AST для создания и восстановления вышеуказанного шаблона, я полагаю, что это будет другой опыт), объединение строк функций рендеринга в соответствии с атрибутами каждого узла, например как: в шаблоне есть v-if="isVisiable", то этот узел в AST будет иметь атрибут if, так что при создании VNode, соответствующего этому узлу, будет

(isVisiable) ? _c('div') : _e()

Под действием с,isVisiableЗначение определяет, генерируется ли VNode. Конечно, некоторые инструкции не могут быть обработаны во время компиляции, они будут смонтированы на виртуальном узле при создании виртуального узла и подвергнуты дальнейшей обработке при разборе виртуального узла, например, v-show и v-on.

Ниже приведены рендеринг и staticRender, сгенерированные вышеуказанным шаблоном:

// render函数
(function anonymous() {
    with (this) {
        return _c('div', {
            directives: [{
                name: "show",
                rawName: "v-show",
                value: (isShow),
                expression: "isShow"
            }],
            staticClass: "Test",
            class: classObj
        }, [_v("\n          " + _s(username) + ":" + _s(password) + "\n          "), _m(0), _v(" "), (isVisiable) ? _c('div', {
            on: {
                "click": onClick
            }
        }) : _e(), _v(" "), _l((items), function(item) {
            return _c('div', [_v(_s(item))])
        })], 2)
    }
}
)
// staticRender
(function anonymous() {
 with (this) {
  return _c('div', [_c('span', [_v("hahhahahha")])])
 } 
}
)

Если это экземпляр компонента, _c и _v используются для создания VNode и строки соответственно, например, имя пользователя и пароль — это состояние, которое передается, когда компонент определяется и монтируется на нем.

3. платформа

Платформенный модуль связан с конкретными платформами. Здесь мы можем определить интерфейсы, связанные с платформой, чтобы передать их во время выполнения и скомпилировать для достижения настройки конкретных платформ, поэтому он предоставляет возможности Vue для других платформ. Большая часть работы здесь.

То, что нужно передать в среду выполнения,Как создавать определенные элементы платформы, взаимосвязь между элементами платформы и как добавлять, вставлять, удалять элементы платформы и т. д., атрибуты, которые необходимо выполнить после создания элементов, мониторинг событий и т. д.. Взяв в качестве примера веб-платформу, нам нужно передать document.createElement, document.createTextNode и сгенерировать HTML-элементы при обходе vnode, вставитьBefore при монтировании, удалить, добавить и т. д., когда различия vnode вызваны изменениями состояния. После создания HTML-элементов используйте setAttribute и removeAttribute для работы с атрибутами, addEventListener и removeEventListener для мониторинга событий, предоставьте некоторые пользовательские компоненты и инструкции, полезные для использования веб-платформы, и т. д.

То, что нужно передать при компиляции, правильноОбработка некоторых специальных атрибутов или директив во время компиляции. Например, веб-платформа требует специальной обработки класса, стиля и модели, чтобы отличить их от общих атрибутов HTML; она предоставляет специфичные для веб-платформы инструкции, v-html (после компиляции это фактически innerHTML связанного элемента), v-text (после компиляции фактически это textContent элемента привязки), v-model, эти инструкции зависят от конкретного элемента платформы.

3. Применение

Сказав так много, конечная цель состоит в том, чтобыПовторно используйте ядро ​​​​Vue и скомпилируйте его, чтобы перенести Vue или Vue-подобный опыт разработки на другие платформы., я также упомянул много примеров успешного повторного использования.Если вы хотите перенести опыт разработки Vue на определенную платформу, вы можете обратиться к нему. В соответствии с концепцией большого внешнего интерфейса терминальные интерфейсы, такие как автомобильные дисплеи и умные часы, могут быть разработаны с помощью Vue в определенный день. Итак, как использовать его повторно? Конечно, я только говорю, что требуется, вы можете настроить все более сложные функции для облегчения использования конкретных платформ.

  1. ДЕТАЛИРУЕМЫЙ vnode генерирующий элемент определяет необходимый платформенный nodeOps, т.е. удаляет элементы, изменяет поиск, для web nodeOps это создает, перемещает, реальные объекты dom, если другие платформы, методы работы этих элементов могут определять свои собственные;

  2. Определите модули, необходимые vnode для создания определенных элементов платформы.Для Интернета модули — это метод, используемый для управления атрибутами dom;

  3. Конкретная платформа должна определить свой собственный метод $mount для Vue, чтобы смонтировать компонент к существующему элементу;

  4. Существуют также некоторые методы, такие как isReservedTag, независимо от того, является ли это зарезервированным именем тега, и имя пользовательского компонента не может совпадать с этим; mustUseProp, который определяет, что свойство элемента должно быть привязано к состоянию компонента, а не постоянная и т.д.;

4. Резюме

В индустрии программного обеспечения есть известная поговорка, что нет проблемы, которую нельзя было бы решить, добавив один слой абстракции.Если есть, то есть два слоя.Такова конструкция Vue (возможно, Vue тоже позаимствован у других) , и уровень абстракции компиляции AST соединяет синтаксис шаблона, а функция рендеринга через уровень абстракции VNode освобождает ядро ​​от конкретной платформы.

Конечная цель этой статьи — сообщить всем, что повторное использование ядра и компиляция исходного кода Vue для вторичной разработки может принести Vue или Vue-подобный опыт разработки на определенные платформы. Конечно, это всего лишь идея, может быть, когда-нибудь опыт разработки в стиле Vue перестанет быть популярным, поэтому мы сможем применить эту идею и к новому стилю разработки.


Подпишитесь на официальный аккаунт [IVWEB Community], чтобы получать свежие статьи каждую неделю, ведущие к вершине жизни!