Рендеринг холста на основе виртуального дома

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

Подробности проекта

адрес гитхаба:github

демонстрационный пример:demo

задний план

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

  1. написать строкуdom templateЭтикетка
  2. оказыватьtemplateсталиdomЭтикетка
  3. начать захватdomэлемент, рисоватьcanvas
  4. canvasРендерить картинки

Основная проблема заключается в том, что повторное использование слишком плохое, а вторая - проблема производительности. Интерфейс, который видит пользователь, не обязательно такой же, как официально отображаемый интерфейс, и могут рендерировать различия. Потому что я в основном используюvue,правильноvueОсновная идея также была в некоторой степени изучена.vueпройти черезvnodeРеализована работа по рендерингу на разных концах, можно ли пройтиvnodeКак насчет рендеринга на холст? то есть нетvnode -> html -> canvasНо прямоvnode -> canvas. использовать одновременноvueна основе данных, чтобы добиться рендеринга на основе данных. Как только у вас появится идея, приступим к ее реализации.

исследование

В этой статье подробнее об этом:60 FPS on the mobile webВот краткий обзор:

Canvas — это метод рендеринга в немедленном режиме, который не хранит дополнительную информацию о рендеринге. Canvas выигрывает от немедленного режима, позволяющего отправлять команды рисования непосредственно на графический процессор. Но использование его для создания пользовательских интерфейсов требует более высокого уровня абстракции. Например, некоторые простые вещи, такие как отрисовка асинхронно загружаемого ресурса в элемент, могут вызвать проблемы, например отрисовка текста поверх изображения. В HTML это легко сделать благодаря порядку элементов и z-индексу в CSS. Рендеринг DOM — это сохраненный режим, сохраненный режим — это декларативный API для поддержки иерархии нарисованных в нем объектов. Преимущество API сохраненного режима заключается в том, что с их помощью обычно проще создавать сложные сценарии, такие как DOM, для вашего приложения. Обычно это связано с затратами на производительность, требуется дополнительная память для сохранения и обновления сцены, что может быть медленным.

Начинать!

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

обрабатывать vnode

Те, кто знаком с исходным кодом Vue, должны знать, что Vue передаетrenderфункция, пройти вcreateElementметод построенияvnode,пройти через发布--订阅режим для мониторинга данных и регенерацииvnode. Все, что нам нужно сделать, этоvnodeЭтот слой начинается. Поэтому мы реализуем функцию слушателя на основе исходного кода Vue и смешиваем ее с экземпляром Vue:

Vue.mixin({
    // ...
    created() {
      if (this.$options.renderCanvas) {
        // ...
        // 监听vnode中引用的变化,重新渲染
        this.$watch(this.updateCanvas, this.noop)
        // ...
      }
    },
    methods: {
      updateCanvas() {
        // 模拟Vue render 函数
        // 寻找实例中定义的 renderCanvas 方法,并传入createElement方法
        let vnode = this.$options.renderCanvas.call(this._renderProxy, this.$createElement)
      }
})

Таким образом, мы можем с радостью использовать внутри компонента:

renderCanvas (h) {
  return h(...)
}

обработка элемента холста

Для vnode рендеринга нам нужно сделать некоторые дополнительные ограничения, такие какdomизdivдолжен соответствоватьcanvasчто там,domтекст внутри, соответствующийcanvasчто внутри... То есть мы можем сделать это с некоторыми ограничениями:

пользовательский ярлык чертежная форма аналогия дом
view/scrollView/scrollItem rect div
text text span
image img img

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

Реализация механизма компоновки объектов рисования

Самый простой способ нарисовать макет холста — передать ряд координатных точек и связанных с ними базовых значений ширины и высоты для элемента холста, который в реальном проекте может выглядеть следующим образом:

renderCanvas(h) {
  return h('view', {
     style: {
       left: 10,
       top: 10,
       width: 100,
       height: 100
     }
  })
}

Действительно, писать таким образом немного неудобно, на данный момент есть несколько решений, одно из них — использоватьcss-layoutзаниматься управлением.css-layoutПоддерживаемые свойства преобразования:

image

Это всего лишь слой преобразования, который поможет нам лучше писать холст с помощью CSS, но если мы очень недовольныcss in jsНа самом деле, мы также можем написать загрузчик веб-пакетов для загрузки внешнего css:

const css = require('css')
module.exports = function (source, other) {
  let cssAST = css.parse(source)
  let parseCss = new ParseCss(cssAST)
  parseCss.parse()
  this.cacheable();
  this.callback(null, parseCss.declareStyle(), other);
};

class ParseCss {
  constructor(cssAST) {
    this.rules = cssAST.stylesheet.rules
    this.targetStyle = {}
  }

  parse () {
    this.rules.forEach((rule) => {
      let selector = rule.selectors[0]
      this.targetStyle[selector] = {}
      rule.declarations.forEach((dec) => {
        this.targetStyle[selector][dec.property] = this.formatValue(dec.value)
      })
    })
  }

  formatValue (string) {
    string = string.replace(/"/g, '').replace(/'/g, '')
    return string.indexOf('px') !== -1 ? parseInt(string) : string
  }

  declareStyle (property) {
    return `window.${property || 'vStyle'} = ${JSON.stringify(this.targetStyle)}`
  }
}

Главное преобразовать файл css вASTСинтаксическое дерево, а затем преобразовать синтаксическое дерево вcanvasТребуемая форма определения. и внедряется в компонент как переменная.

Реализовать прокрутку списка

Если у нас много элементов и нам нужно прокрутить, мы должны решитьcanvasПроблемы с прокруткой внутренних элементов. Здесь я предпочитаю использоватьZynga ScrollerЧтобы имитировать метод прокрутки пользователя, холст перерисовывается через возвращенные им координаты прокрутки.

подробныйобратитесь сюда

моделирование событий

дляclick,touchДля моделирования событий dom решение, которое мы принимаем, состоит в том, чтобы обнаружить в соответствии с областью, по которой щелкнули, найти самый нижний элемент, рекурсивно найти родительский элемент и вызвать соответствующий обработчик событий, тем самым имитируя всплытие событий.

Подробная реализация может бытьобратитесь сюда

наконец

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

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