Функции рендеринга и JSX

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

Если вы не знакомы с концепцией виртуального DOM и функциями рендеринга, обязательно сначала прочитайте главу Механизм рендеринга.

Что такое API композиции?

Composition API — это набор API, который позволяет нам создавать компоненты Vue, используя импортированные функции вместо объявления параметров. Это общий термин, который охватывает следующие API:

  • API реактивности, например. ref() и reactive(), что позволяет нам напрямую создавать реактивное состояние, вычисляемое состояние и наблюдателей.
  • Крючки жизненного цикла, например. onMounted() и onUnmounted(), что позволяет нам программно подключиться к жизненному циклу компонента.
  • Внедрение зависимостей, то есть provide() и inject(), что позволяет нам использовать систему внедрения зависимостей Vue при использовании API реактивности.

Composition API — это встроенная функция Vue 3, которая в настоящее время доступна для Vue 2 через официально поддерживаемый плагин @vue/composition-api. В Vue 3 он также в основном используется вместе с синтаксисом <script setup> в однофайловых компонентах. Вот базовый пример компонента, использующего Composition API:

<script setup>
import { ref, onMounted } from 'vue'
// reactive state
const count = ref(0)
// functions that mutate state and trigger updates
function increment() {
  count.value++
}
// lifecycle hooks
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

Несмотря на стиль API, основанный на композиции функций, Composition API НЕ является функциональным программированием. Composition API основан на изменчивой, детализированной парадигме реактивности Vue, тогда как функциональное программирование делает упор на неизменность.

Если вы хотите узнать, как использовать Vue с Composition API, вы можете установить предпочтение API для всего сайта на Composition API, используя переключатель в верхней части левой боковой панели, а затем пройти руководство с самого начала.

Читать полную документацию https://vuejs.org/

Создадим сценарий. Еще во Vue 2 я вызывал render() следующим образом:

export default {
  mounted(){
   ...
  },
  render(){
    ...
  },
  methods(){
    ...
  }
}

Сейчас я пытаюсь сделать то же самое с Vue 3 и API композиции. Вот что я пробовал:

<script>
export default {
  ...
    setup(props, context) {
...
  const create_canvas = (h, id, props) => {
    _id.value = id
    _attrs.value = props.attrs
    return () => h('div', {
      class: `trading-vue-${id}`,
      style: {
        left: props.position.x + 'px',
        top: props.position.y + 'px',
        position: 'absolute',
      }
    }, [
      h('canvas', Object.assign({
        id: `${props.tv_id}-${id}-canvas`,
        onmousemove: e => renderer.mousemove(e),
        onmouseout: e => renderer.mouseout(e),
        onmouseup: e => renderer.mouseup(e),
        onmousedown: e => renderer.mousedown(e),
        ref: 'canvas',
        style: props.style,
      }, props.attrs))
    ].concat(props.hs || []))
  };
  function render() {
    const id = props.grid_id
    const layout = props.layout.grids[id]
    return () => create_canvas(h, `grid-${id}`, {
      position: {
        x: 0,
        y: layout.offset || 0
      },
      attrs: {
        width: layout.width,
        height: layout.height,
        overflow: 'hidden'
      },
      style: {
        backgroundColor: props.colors.back
      },
      hs: [
        h(Crosshair, Object.assign(
          common_props(),
          layer_events
        )),
        h(KeyboardListener, keyboard_events),
        h(UxLayer, {
          id,
          tv_id: props.tv_id,
          uxs: uxs.value,
          colors: props.colors,
          config: props.config,
          updater: Math.random(),
          onCustomEvent: emit_ux_event
        })
      ].concat(get_overlays(h))
    })
  };
  render()
}
}
</script>

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

Насколько я понимаю, h() — это короткая форма для создания vnodes и приема 3 параметров.

h(
 tag name,
 props/attributes,
 array of children
)

Насколько я понимаю, в create_canvas вы пытаетесь создать div, который содержит класс и встроенные стили в качестве реквизита/атрибутов, и мы создаем холст как дочерние элементы этого vnode div. Следовательно, вместо того, чтобы возвращать vNode непосредственно из setup(), он должен возвращать функцию рендеринга, которая возвращает vNode.

<script>
export default {
  props: {
// props will come here
  },
  setup(props) {
// render() { h(...) } ❌
    return () => {
      h('div', {
        class: `trading-vue-${id}`,
        style: {
          left: props.position.x + 'px',
          top: props.position.y + 'px',
          position: 'absolute',
        }
      }, [
        h('canvas', Object.assign({
          id: `${props.tv_id}-${id}-canvas`,
          onmousemove: e => renderer.mousemove(e),
          onmouseout: e => renderer.mouseout(e),
          onmouseup: e => renderer.mouseup(e),
          onmousedown: e => renderer.mousedown(e),
          ref: 'canvas',
          style: props.style,
        }, props.attrs))
      ].concat(props.hs || []))
    } ✅
  }
}
</script>

Это может помочь вызвать функции рендеринга в API композиции vue 3.