Введение в Vue Render и несколько основных примеров

внешний интерфейс JavaScript Vue.js

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

Vue рекомендует использовать шаблоны для создания вашего HTML в подавляющем большинстве случаев. Однако в некоторых сценариях вам действительно нужны все возможности программирования JavaScript, т.е.функция рендеринга, который ближе к компилятору, чем template .(Скопировано с официального сайта, я сильно запаниковал.На самом деле это просто писать HTML в виде функций, что более управляемо~)

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

В этой статье в основном представлены следующие моменты

Гостевые офицеры, которые понимают основные концепции, могут напрямую перейти к экземпляру, который был загружен на github.

  • виртуальный DOM
  • Функция CreateElement
  • [Начало] Самый простой пример
  • [Дополнительно] Содержит более полный экземпляр конфигурации атрибута
  • [Дополнительно] СоздатьЭлементslotИспользование атрибута
  • [Подробно] CreateElementscopedSlotsПрименение
  • [Изменение дыхания] Конфигурация JSX и использование в рендере
  • 【Подробно】Функциональные компоненты

Гитхаб-портал

виртуальный DOM

1,Что такое ДОМ?

DOM — это логический объект в форме дерева, полученный браузерами при разборе HTML.

2,Что такое виртуальный DOM?

Используйте Object для представления узла.Этот узел называется виртуальным узлом (Virtual Node), сокращенно VNode, а виртуальный DOM состоит из дерева VNode.

3.Зачем использовать виртуальный DOM?

Суть большинства операций и логики веб-страниц заключается в постоянном изменении элементов DOM, но операции DOM слишком медленные, а слишком частые операции DOM могут привести к тому, что вся страница пропустит кадры, зависнет или даже потеряет отклик. Подумайте об этом внимательно, многие операции DOM могут быть упакованы (несколько операций сжимаются в одну) и объединены (одна непрерывная операция обновления сохраняет только конечный результат), а скорость вычислений движка JS намного выше, так почему бы не манипулировать DOM После завершения вычислений JS мы будем оперировать DOM одним большим движением, поэтому у нас есть концепция виртуального DOM. Конечно, ядром операции виртуального DOM является алгоритм Diff, который сравнивает разницу между Vnodes до и после изменения и вычисляет минимальную операцию DOM для изменения DOM и повышения производительности.

4.Как генерируется виртуальный DOM в Vue?

Через `createElement(tag, options, VNodes)` ниже представлена ​​основная концепция этой функции.

Функция CreateElement

Проще говоря, CreateElement — это функция, используемая для создания Vnode.

Что именно возвращает CreateElement? На самом деле это не настоящий элемент DOM (возвращает Vnode). Его более точное имя может быть createNodeDescription, поскольку оно содержит информацию, которая сообщает Vue, какой тип узла отображать на странице и его дочерние элементы.

【Советы】 CreateElementФункции также обычно записываются в соглашенииh

1,Параметры CreateElement следующие::(Слишком лениво переносить официальный сайт напрямую)
// @returns {VNode}
createElement(
  // {String | Object | Function}
  // 一个 HTML 标签字符串,组件选项对象,或者 解析上述任何一种的一个 async 异步函数,必要参数。
  'div',

  // {Object}
  // 一个包含模板相关属性的数据对象
  // 这样,您可以在 template 中使用这些属性。可选参数。
  {
    // 详情见下方
  },

  // {String | Array}
  // 子节点 (VNodes),由 `createElement()` 构建而成,或使用字符串来生成“文本节点”。可选参数。
  [
    '先写一些文字',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

【Советы】В документе говорится, что дочерние узлы VNodes должны быть уникальными, то есть VNodes с одинаковым указанием не могут появляться в массиве третьего параметра.После фактической проверки, даже если будут записаны повторяющиеся VNodes, об ошибке не будет сообщено. Предполагается, что будут некоторые ямы, на которые еще не наступили.Рекомендуется сохранить дочерние узлы уникальными в соответствии с требованиями документа.

2. Конфигурация свойства Vnode (второй параметр): (Слишком ленив, чтобы двигать его напрямую, прикрой мое лицо.jpg)

Следующие атрибуты представляют собой краткое введение, конкретное использование и некоторые _примечания, пояснения _ могут относиться к [включая более полные примеры конфигурации атрибутов], которые будут упомянуты позже.

{
  // 和`v-bind:class`一样的 API
  // 接收一个字符串、对象或字符串和对象组成的数组
  'class': {
    foo: true,
    bar: false
  },
  // 和`v-bind:style`一样的 API
  // 接收一个字符串、对象或对象组成的数组
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 正常的 HTML 特性
  attrs: {
    id: 'foo'
  },
  // 组件 props
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器基于 `on`
  // 所以不再支持如 `v-on:keyup.enter` 修饰器
  // 需要手动匹配 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅对于组件,用于监听原生事件,而不是组件内部使用
  // `vm.$emit` 触发的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
  // 赋值,因为 Vue 已经自动为你进行了同步。
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // 作用域插槽格式
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其他组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其他特殊顶层属性
  key: 'myKey',
  ref: 'myRef'
}

[Начало] Самый простой пример

Это базовая демонстрация, которая включает в себя

  • Простое использование рендеринга

  • Этикетка

  • props

  • slot

  • событие щелчка

Во всех следующих демонстрационных примерах используется метод компонента с одним файлом, который используется для проектирования.vue-cliпостроенwebpack-simpleпроект.

компонентыwii-first

<script>
export default {
  name: 'wii-first',
  data() {
    return {
      msg: 0
    }
  },
  props: {
    level: {
      type: [Number, String],
      required: true
    }
  },
  render: function(createElement) {
    this.$slots.subtitle = this.$slots.subtitle || []
      // this.level = 1时, 等价于
      // <h1 class="wii-first">
      //  第一个组件, <slot></slot>
      //  <slot name="subtitle"></slot>,此处是data的值: {{msg}}
      //  <button @click="clickHandler">点我改变内部data值</button>
      // </h1>
    return createElement(
      'h' + this.level, // tag name 标签名称
      {
        class: 'wii-first'
      },
      // this.$slots.default, // 子组件中的slot 单个传递
      // this.$slots.subtitle,
      [
        '第一个组件, ',
        ...this.$slots.default, // 默认slots传递
        ...this.$slots.subtitle, // 具名slots传递
        ',此处是data的值: ',
        this.msg,
        createElement('button', {
          on: {
            click: this.clickHandler
          },
        }, '点我改变内部data值')
      ]
    )
  },
  methods: {
    clickHandler() {
      this.msg = Math.ceil(Math.random() * 1000)
    }
  }
}
</script>

[Советы]: Третий параметр CreateElement указывает в документе, что все виртуальные узлы в дереве компонентов должны быть уникальными, то есть недопустимо наличие двух виртуальных узлов, указывающих на одно и то же в третьем параметре. Но после практики выясняется, что это действительно может быть отрендерено.Так писать здесь не рекомендуется.Это может попасть в непредсказуемую яму хахахия~

метод введения

<template>
  <div id="app">
    <wii-first level="1">我是标题 <span slot="subtitle">我是subtitle</span></wii-first>
  </div>
</template>

<script>
import WiiFirst from './components/first/index.vue'
export default {
  name: 'app',
  components: {
    WiiFirst
  },
  data() {
    return {

    }
  }
}
</script>

[Дополнительно] Содержит более полный экземпляр конфигурации атрибута

Эта демонстрация в основном показывает использование свойства createElement, в том числе

  • класс, стиль, атрибуты, включение и т. д.
  • содержит события кликов иclick.stopПример преобразования

не содержит

  • Реализация v-for v-if v-model подробно описана на официальном сайте.портал

компонентыwii-second

export default {
  name: 'wii-second',
  data() {
    return {
      myProp: '我是data的值, 只是为了证明props不是走这儿'
    }
  },
  props: {

  },
  render: function(createElement) {
    // 等价于
    // <div id="second" class="wii-second blue-color" style="color: green;" @click="clickHandler">
    //     我是第二个组件测试, 点我触发组件内部click和外部定义的@click.native事件。
    //     <div>{{myProp}}</div>
    //     <button @click="buttonClick">触发emit</button>
    // </div>
    return createElement(
      'div', {
        //【class】和`v-bind:class`一样的 API
        // 接收一个字符串、对象或字符串和对象组成的数组
        // class: 'wii-second',
        // class: {
        //     'wii-second': true,
        //     'grey-color': true
        // },
        class: [{
          'wii-second': true
        }, 'blue-color'],

        //【style】和`v-bind:style`一样的 API
        // 接收一个字符串、对象或对象组成的数组
        style: {
          color: 'green'
        },
        //【attrs】正常的 HTML 特性, id、title、align等,不支持class,原因是上面的class优先级最高[仅猜测]
        // 等同于DOM的 Attribute
        attrs: {
          id: 'second',
          title: '测试'
        },
        // 【props】组件 props,如果createElement定义的第一个参数是组件,则生效,此处定义的数据将被传到组件内部
        props: {
          myProp: 'bar'
        },
        // DOM 属性 如 value, innerHTML, innerText等, 是这个DOM元素作为对象, 其附加的内容
        // 等同于DOM的 Property
        // domProps: {
        //   innerHTML: 'baz'
        // },
        // 事件监听器基于 `on`, 用于组件内部的事件监听
        on: {
          click: this.clickHandler
        },
        // 仅对于组件,同props,等同@click.native,用于监听组件内部原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
        // nativeOn: {
        //   click: this.nativeClickHandler
        // },
        // 如果组件是其他组件的子组件,需为插槽指定名称,见 wii-third 组件
        // slot: 'testslot',
        // 其他特殊顶层属性
        // key: 'myKey',
        // ref: 'myRef'
      }, [
        `我是第二个组件测试, 点我触发组件内部click和外部定义的@click.native事件。`,
        createElement('div', `${this.myProp}`),
        createElement('button', {
          on: {
            click: this.buttonClick
          }
        }, '触发emit')
      ]
    )
  },
  methods: {
    clickHandler() {
      console.log('我点击了第二个组件,这是组件内部触发的事件')
    },
    buttonClick(e) {
      e.stopPropagation() // 阻止事件冒泡 等价于 click.stop
      console.log('我点击了第二个组件的button,将会通过emit触发外部的自定义事件')
      this.$emit('on-click-button', e)
    }
  }
}

метод введения

<template>
  <div id="app">
    <wii-second @click.native="nativeClick" @on-click-button="clickButton"></wii-second>
  </div>
</template>

<script>
import WiiSecond from './components/second/index.vue'

export default {
  name: 'app',
  components: {
    WiiSecond
  },
  data() {
    return {
    }
  },
  methods: {
    nativeClick() {
      console.log('这是组件外部click.native触发的事件,第二个组件被点击了')
    },
    clickButton() {
      console.log('这是组件外部触发的【emit】事件,第二个组件被点击了')
    }
  }
}
</script>

События и клавиши-модификаторы

используется в приведенном выше примереe.stopPropagationЭтот метод эквивалентен методу написания шаблона шаблонаclick.stop, другие события и ключевые модификаторы также имеют соответствующие методы, соответствующие ситуации следующие.

Префикс, соответствующий модификатору события

модификатор события шаблона визуализировать префикс записи
.passive &
.capture !
.once ~
.capture.once или .once.capture ~!

Например

on: {
  '!click': this.doThisInCapturingMode,
  '~keyup': this.doThisOnce,
  '~!mouseover': this.doThisOnceInCapturingMode
}

Другие модификаторы событий, метод события используется в соответствующем обработчике события

модификатор события шаблона Соответствующий метод события
.stop event.stopPropagation()
.prevent event.preventDefault()
.self if (event.target !== event.currentTarget) return
Keys: .enter, .13 if (event.keyCode !== 13) return (для других модификаторов событий клавиатуры просто замените 13 другими кодами клавиатуры)
Modifiers Keys: .ctrl, .alt, .shift, .meta if (! event.ctrlKey) return (ctrlKey заменил altKey, shiftKey или metaKey соответственно)

Например

on: {
  keyup: function (event) {
    // 如果触发事件的元素不是事件绑定的元素
    // 则返回
    if (event.target !== event.currentTarget) return
    // 如果按下去的不是 enter 键或者
    // 没有同时按下 shift 键
    // 则返回
    if (!event.shiftKey || event.keyCode !== 13) return
    // 阻止 事件冒泡
    event.stopPropagation()
    // 阻止该元素默认的 keyup 事件
    event.preventDefault()
    // ...
  }
}

[Дополнительно] СоздатьЭлементslotИспользование атрибута

Эта демонстрация в основном показывает использование атрибута слота конфигурации createElement в рендеринге.

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

компонентыwii-third

<script>
export default {
  name: 'wii-third',
  data() {
    return {}
  },
  components: {
    WiiTestSlot: {
      name: 'wii-test-slot',
      render(createElement) {
        this.$slots.testslot = this.$slots.testslot || []
          // 等价于
          // <div>
          //     第三个组件,测试在组件中定义slot, <slot name="testslot"></slot>
          // </div>
        return createElement(
          'div', [
            '第三个组件,测试在组件中定义slot, ',
            ...this.$slots.testslot
          ]
        )
      }
    },
    WiiTestSlotIn: {
      name: 'wii-test-slot-in',
      render(createElement) {
        // 等价于
        // <span>我是组件中的slot内容</span>
        return createElement(
          'span', [
            '我是组件中的slot内容'
          ]
        )
      }
    }
  },
  props: {

  },
  render: function(createElement) {
    // 等价于
    // <div style="margin-top: 15px;">
    //     <wii-test-slot>
    //       <wii-test-slot-in slot="testslot"></wii-test-slot-in>
    //     </wii-test-slot>
    // </div>
    return createElement(
      'div', {
        style: {
          marginTop: '15px'
        }
      }, [
        createElement(
          'wii-test-slot',
          //这么写不会被渲染到节点中去
          // createElement(
          //    'wii-test-slot-in',
          //    {
          //      slot: 'testslot'
          //    }
          //  ),
          [
            // createElement再放createElement需要放入数组里面,建议所有的组件的内容都放到数组里面,统一格式,防止出错
            createElement(
              'wii-test-slot-in', {
                slot: 'testslot'
              }
            )
          ]
        )
      ]
    )
  },
  methods: {

  }
}
</script>

[Советы]: Если третий параметр в createElement передает объект VNode, сгенерированный createElement, он не будет отображаться в узле и должен быть помещен в массив, чтобы он вступил в силу.Предполагается, что объект VNode не будет напрямую распознается. , поскольку в документации требуется строка или массив.

метод введения

<template>
  <div id="app">
    <wii-third></wii-third>
  </div>
</template>

<script>
import WiiThird from './components/third/index.vue'

export default {
  name: 'app',
  components: {
    WiiThird
  },
  data() {
    return {}
  }
}
</script>

[Подробно] CreateElementscopedSlotsПрименение

Эта демонстрация в основном показывает использование scopedSlots, включая определение и использование. Справочник по использованию и объяснению шаблонов для scopedSlotsvue-slot-scope.

компонентыwii-forth

<script>
export default {
  name: 'wii-forth',
  data() {
    return {}
  },
  components: {
    WiiScoped: {
      name: 'wii-scoped',
      props: {
        message: String
      },
      render(createElement) {
        // 等价于 <div><slot :text="message"></slot></div>
        return createElement(
          'div', [
            this.$scopedSlots.default({
              text: this.message
            })
          ]
        )
      }
    }
  },
  render: function(createElement) {
    // 等价于 
    // <div style="margin-top: 15px;">
    //   <wii-scoped message="测试scopedSlots,我是传入的message">
    //     <span slot-scope="props">{{props.text}}</span>
    //   </wii-scoped>
    // </div>
    return createElement(
      'div', {
        style: {
          marginTop: '15px'
        }
      }, [
        createElement('wii-scoped', {
          props: {
            message: '测试scopedSlots,我是传入的message'
          },
          // 传递scopedSlots,通过props(自定义名称)取值
          scopedSlots: {
            default: function(props) {
              return createElement('span', props.text)
            }
          }
        })
      ]
    )
  }
}
</script>

метод введения

<template>
  <div id="app">
    <wii-forth></wii-forth>
  </div>
</template>

<script>
import WiiForth from './components/forth/index.vue'

export default {
  name: 'app',
  components: {
    WiiForth
  },
  data() {
    return {}
  }
}
</script>

[Изменение дыхания] Конфигурация JSX и использование в рендере

После написания такого количества createElements у меня устают глаза, а писать некоторые довольно хлопотно. Попробуем изменить вкус и попробовать способ написания JSX.

Если рабочий хочет хорошо работать, он должен сначала заточить свои инструменты.

  • Сначала мы устанавливаем необходимые зависимости для vue для написания JSX:
npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-env --save-dev
  • После завершения установки в.babelrcконфигурация файла"plugins": ["transform-vue-jsx"].

  • Измените раздел синтаксического анализа js в файле конфигурации веб-пакета наtest: /\.jsx?$/Представляет разбор блока кода jsx.

Этот пример делает следующее:

  1. Передайте цвет через реквизит и настройте его в дочернем компоненте.
  2. Нажмите, чтобы изменить цвет
  3. Событие клика получается через родной

родительский компонентwii-jsx

<script type="text/jsx">
     import WiiJsxItem from './item.vue'
     export default {
        name: 'wii-jsx',
        components: {
            WiiJsxItem
        },
        data() {
            return {
                color: 'red'
            }
        },
        props: {

        },
        render: function (h) {
        return (
            <div class="wii-jsx">
                <wii-jsx-item color={this.color} nativeOnClick={this.clickHandler}>
                    <span>我是wii-jsx-item组件的slot, color通过变量传入: {this.color}</span>
                </wii-jsx-item>
            </div>
        )
      },
      methods: {
          clickHandler() {
            this.color = this.color == 'red' ? 'blue' : 'red'
            console.log(`点击了wii-jsx-item,通过native触发,改变了颜色为【${this.color}】`)
          }
      }
    }
</script>

Подсборкаwii-jsx-item

Дочерний компонент импортируется в родительский компонент и отображается в нотации JSX.

export default {
  name: 'wii-jsx-item',
  data() {
    return {}
  },
  props: {
    color: String
  },
  render: function(createElement) {
    // 等价于 <div class="wii-jsx-item"><slot></slot></div>
    return createElement(
      'div', {
        class: 'wii-jsx-item',
        style: {
          color: this.color
        }
      },
      this.$slots.default
    )
  },
  methods: {

  }
}

метод введения

<template>
  <div id="app">
    <wii-jsx></wii-jsx>
  </div>
</template>

<script>
import WiiJsx from './components/jsx/index.vue'

export default {
  name: 'app',
  components: {
    WiiJsx
  },
  data() {
    return {}
  }
}

Основное преобразование JSX по-прежнему зависит от того, что мы установили ранее.Плагин Бабель, а использование событий и свойств JSX см. в подключаемом модуле babel.Инструкции по применению, который содержит инструкции по использованию, соответствующие событиям и атрибутам в vue.

【Подробно】Функциональные компоненты

Давайте представим последний модуль, функционал функционального компонента, использование этой вещи зависит от мнения, здесь нет хорошего решения, просто приведите несколько примеров, если у вас есть какие-то конкретные места для использования, Куо, чтобы указать wow~thx ~(застенчивый.jpg).

Определение из официальной документации состоит в том, что все, что нужно функциональному компоненту, передается через контекст, в том числе:

  • реквизит: объект, предоставляющий все реквизиты
  • Children: массив дочерних узлов VNode
  • слоты: функция, которая возвращает объект всех слотов
  • data: объект данных, переданный компоненту, переданный в компонент в качестве второго параметра createElement
  • parent: ссылка на родительский компонент
  • listeners: (2.3.0+) Объект, содержащий все прослушиватели событий, зарегистрированные в родительском компоненте. Это просто псевдоним data.on .
  • инъекции: (2.3.0+) Если используется опция инъекции, этот объект содержит свойства, которые должны быть внедрены.

_ добавляет _functional: trueПосле этого функция рендеринга компонента добавит второй параметр context (первый — createElement), а данные и узлы передаются через контекст.

Советы:

В версиях до 2.3.0, если функциональный компонент хотел принимать свойства, тоpropsопция обязательна. В версии 2.3.0 и выше можно не указыватьpropsОпции, свойства на всех компонентах автоматически разрешаются как реквизиты.


Мое личное понимание:

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

преимущество:

Поскольку функциональный компонент — это просто функция, накладные расходы на рендеринг намного ниже.

используемые сцены:

  1. Используется только как компонент для получения параметров (без какого-либо управления и состояния мониторинга)
  2. В настоящее время большинство сценариев использования используются для переноса компонентов анимации, поскольку компоненты анимации не требуют управления состоянием.
  3. Программно выберите один из нескольких компонентов (официальный)
  4. Манипулировать дочерними элементами, реквизитами, данными перед передачей их дочерним компонентам (официально)

Далее давайте посмотрим, как использовать два компонента. Это всего лишь пример. Сценарии использования все еще изучаются. Конкретные сценарии использования необходимо выбирать в соответствии со сложными требованиями и требованиями к производительности в процессе разработки. ~

функциональный компонент одинwii-functionalфункционал для анимации

Функция этого Демо состоит в том, чтобы ввести символы в поле ввода, отфильтровать список данных и добавить анимацию отображения и исчезновения при фильтрации.

тело компонента

<script>
import Velocity from 'velocity-animate' // 这是一个动画库
export default {
  name: 'wii-functional',
  functional: true, //表明是函数式组件
  render: function(createElement, context) {
    // context是在functional: true时的参数
    let data = {
      props: {
        tag: 'ul',
        css: false
      },
      on: {
        // 进入前事件
        beforeEnter: function(el) {
          el.style.opacity = 0
          el.style.height = 0
        },
        // 进入事件
        enter: function(el, done) {
          let delay = el.dataset.index * 150
          setTimeout(function() {
            Velocity(el, {
              opacity: 1,
              height: '1.6em'
            }, {
              complete: done
            })
          }, delay)
        },
        // 离开事件
        leave: function(el, done) {
          let delay = el.dataset.index * 150
          setTimeout(function() {
            Velocity(el, {
              opacity: 0,
              height: 0
            }, {
              complete: done
            })
          }, delay)
        }
      }
    }
    return createElement('transition-group', data, context.children)
  }
}
</script>

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

метод введения

<template>
  <div id="app">
    <input v-model="query"/>
    <wii-functional>
      <li v-for="(item, index) in computedList"
          :key="item.msg"
          :data-index="index">
          {{item.msg}}
      </li>
    </wii-functional>
  </div>
</template>

<script>
import WiiFunctional from './components/functional/index.vue'

export default {
  name: 'app',
  components: {
    WiiFunctional
  },
  data() {
    return {
      // 关键字
      query: '',
      // 数据列表
      list: [{
        msg: 'Bruce Lee'
      }, {
        msg: 'Jackie Chan'
      }, {
        msg: 'Chuck Norris'
      }, {
        msg: 'Jet Li'
      }, {
        msg: 'Kung Furry'
      }, {
        msg: 'Chain Zhang'
      }, {
        msg: 'Iris Zhao'
      }, ]
    }
  },
  computed:{
    computedList: function() {
      var vm = this
      // 过滤出符合条件的查询结果
      return this.list.filter(function(item) {
        return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
      })
    }
  },
  watch: {
    computedList(newVal, oldVal) {
      console.log(newVal)
    }
  }
}
</script>

Второй функциональный компонентwii-choose-compфункционал, используемый при переключении компонентов

В этом примере для переключения через другую загрузочную сборку Реквизиты и перед передачей их в операцию подсборки определяются внутренние компоненты, чтобы показать пример в событии click.native props. Если то же самое сделать для ряда компонентов, то можно использовать этот функционал по аналогии с перерабатывающим заводом.

Конечно, если компонент нуждается в различных событиях или методам презентации, вы также можете написать логику или монитор отдельно внутри каждого компонента ~, потому чтоwii-choose-compЭта оболочка, по сути, просто функция~

тело компонентаwii-choose-comp

<script>
export default {
  name: 'wii-choose-comp',
  functional: true,
  props: { // 2.3.0版本以上也可以不写props,会将组件属性默认绑定成props,为了统一标准还是写上
    componentName: String // 组件名
  },
  render: function(createElement, context) {
    // 给组件加上class
    context.data.class = [context.props.componentName]
    
    // 在props传给子组件之前操作它
    context.data.props = {
      compName: context.props.componentName
    }

    context.data.nativeOn = {
      click() {
        alert('我是functional里面统一的点击事件')
      }
    }
    return createElement(context.props.componentName, context.data, context.children)
  }
}
</script>

переключить компонент 1wii-comp-one

<script>
export default {
  name: 'wii-comp-one',
  props: {
    compName: String
  },
  render: function(createElement) {
    return createElement('div', [
      '我是第一个comp, 我有点击效果, ',
      `我的名字叫${this.compName}, `,
      ...this.$slots.default
    ])
  }
}
</script>

переключить компонент 2wii-comp-two

<script>
export default {
  name: 'wii-comp-two',
  props: {
    compName: String
  },
  render: function(createElement) {
    return createElement('div', [
      '我是第二个comp, 点我试试呗, ',
      `我的名字叫${this.compName}, `,
      ...this.$slots.default
    ])
  }
}
</script>

метод введения

<template>
  <div id="app">
    <button @click="changeComponent">点击切换组件</button>
    <wii-choose-comp :component-name="componentName">
      <span>我是{{componentName}}的slot</span>
    </wii-choose-comp>
  </div>
</template>

<script>
import WiiChooseComp from './components/functional/chooseComp.vue'
import WiiCompOne from './components/functional/comp1.vue'
import WiiCompTwo from './components/functional/comp2.vue'

export default {
  name: 'app',
  components: {
    WiiChooseComp,
    WiiCompOne,
    WiiCompTwo
  },
  data() {
    return {
      componentName: 'wii-comp-one'
    }
  },
  methods: {
    changeComponent() {
      this.componentName = this.componentName == 'wii-comp-one' ? 'wii-comp-two' : 'wii-comp-one'
    }
  }
}
</script>

【Советы】Все компоненты, подлежащие переключению, должны быть введены во внешний слой. (Есть ли лучший способ не создавать его?)

Суммировать

Это недавнее исследование Vue Render. Поскольку при разработке общедоступных библиотек компонентов необходимо учитывать множество проблем, требования к гибкости также выше. Если Vue Render используется для написания библиотек компонентов способом, который ближе к компиляции , Это может прояснить логику, хотя способ постоянного создания элементов довольно отвратительный хахахаха~~

Следующий шаг — использовать его в реальном бою.