Vue: Разрешить детям «наследовать» компоненты, зарегистрированные для родителей.

Созданный на 10 сент. 2015  ·  36Комментарии  ·  Источник: vuejs/vue

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

Самый полезный комментарий

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

Все 36 Комментарий

Любой пример использования в реальном мире?

В небольших случаях просто регистрируйте все глобально; в больших приложениях гораздо удобнее поддерживать каждый компонент, явно завися от того, что ему нужно. Это может быть полезно в некоторых ситуациях, но преимущества приходят с глобальным компромиссом. Идея версии 1.0 заключается в том, что «если что-то полезно лишь незначительно или оказывает негативное влияние на ремонтопригодность, давайте удалим это».

Ага. В моем приложении есть всплывающее окно со сложной структурой пользовательских элементов редактора. Эти элементы могут быть объединены в 3-4-уровневую иерархию, что делает неэффективным их явное объявление для каждого родительского элемента (3-5 родительских типов * 10 объявленных элементов = 50 строк повторяющегося кода). И также не стоит регистрировать их глобально, так как они никогда не появятся в других частях приложения. Поэтому я бы хотел, чтобы они загружались «локально».

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

@ yyx990803 У меня хорошая память, спасибо. Итак, я запомню, что мое приложение состоит из двух очень разных частей, каждая из которых регистрирует четко определенный набор специфичных для нее компонентов. Поэтому я бы предпочел иметь выбор, куда загружать мои ресурсы (и я подозреваю, что то же самое произошло с пользовательскими директивами и фильтрами).

Поделюсь впечатлением. Я работал с 0.12.x, и все прошло ОЧЕНЬ хорошо (за исключением некоторых незначительных проблем с обучением). Минималистичный и чистый API, синтаксис, надежный код. Сейчас у нас 1.0.0-бета и стало ХУЖЕ, а не лучше. Больше повторений кода, функции, которые я использую, удалены, что заставляет меня переписывать один и тот же код снова и снова. Я начинаю думать, что совершил ошибку, выбрав Vue вместо React, потому что я не уверен, что в будущем больше не будет критических изменений и пустой траты моего времени.

@karevn

  1. Было бы намного полезнее, если бы вы перечислили конкретные вещи, которые ухудшили работу разработчиков в дополнение к этой проблеме.
  2. 1.0.0-alpha — это предварительные версии, а это означает, что в первую очередь не было гарантии стабильности API. Если вы цените стабильность, вам следует придерживаться версии 0.12 и дождаться стабильной версии 1.0 (у которой также будет окончательный выпуск миграции). Использование предварительной версии означает, что вы согласились иметь дело с постоянными критическими изменениями.
  3. 1.0.0-бета даже не выпущена. Вероятно, не стоит использовать невыпущенную, незавершенную ветку.
  4. Я разрабатываю API на основе своего опыта и отзывов всего сообщества. Вы имеете право на все, что вы думаете, и не стесняйтесь переключаться на другие фреймворки, если изменения не в том направлении, которое вам нравится. (На самом деле, в React вам также придется импортировать все явно, и вам придется повторять еще больше вещей.)
  1. Прочитав обсуждение #1170, теперь почти согласен. Но... я действительно не вижу смысла удалять существующий код, обеспечивающий эту функцию, вместо того, чтобы просто сделать strict: true значением по умолчанию. Вкусы разные, и некоторые люди предпочтут «запасной» подход, который иногда более интуитивен. Особенно, когда компоненты загружаются динамически. Это можно обойти с помощью миксинов, фабрик и т. д., но все это требует драгоценного времени.
  2. Конечно вещь. Но всегда существует баланс между «идеальной архитектурой» и стоимостью изменений. В этом случае несколько строк кода (а именно: около 10), которые никому не повредят, если их оставить, стоили мне значительного времени. И я должен использовать эту нестабильную версию, так как мне действительно нужна функция «фильтров привязки чтения-записи», которые, вероятно, не будут перенесены в 0.12.x.
  3. См. 2.
  4. Вопрос не в том, «какой API я предпочитаю». Я предпочитаю Вью. Период. Вопрос в том, могу ли я полагаться на Vue API в долгосрочной перспективе. Надежность превыше красоты. Если изменения ломаются, для этого должна быть серьезная причина. В случае с новым синтаксисом привязки, который сломал ВЕСЬ мой код — ладно, пусть будет так, он более читаем и требует лучшей структуры кода. В данном случае - нет. Это изменение может быть постоянным, если по умолчанию установлено значение options.strict = true .

Да, обновление всегда сопряжено с трудностями рефакторинга, но 1.0 — это единственный шанс для Vue освободиться от этих устаревших параметров конфигурации. После 1.0 будет строго семвер, и до 2.0 ничего ломаться не должно. И я хочу, чтобы версия 1.x прослужила как можно дольше из-за проблем с надежностью, о которых вы говорили.

Что касается строгого режима: он, безусловно, стоит времени на рефакторинг, когда вы сильно полагались на него, но в идеале для новых пользователей, которые используют Vue после 1.0, им даже не нужно знать, что эта штука существует. Поверхность API должна быть как можно меньше, а глобальный шаблон структурирования должен быть как можно более последовательным. Предоставление возможности отключить строгий режим, по сути, поощряет два разных стиля структурирования приложений Vue — представьте, что люди работают над одним приложением, которое использует strict: true , а затем переходят к другому проекту, который использует strict: false … это создает фрагментация опыта разработчиков, и я хочу избавиться от этой возможности, и 1.0 — единственное разумное место для этого.

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

@ yyx990803 Я вижу конкретный вариант использования, с которым я как бы застрял.

Что я пытаюсь сделать

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

При загрузке виджет добавит динамически созданный компонент в приложение vuejs.
Виджеты могут содержать другие виджеты (дочерние). Мы не знаем, как это будет при запуске, потому что эта часть управляется пользователем после загрузки приложения. Вот почему виджеты должны знать друг о друге и регистрировать другие виджеты.

Проблема

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

var components = {

    appComponents: {
       template: "...",
       components: components
    },

    appComponents2: {
       template: "...",
       components: components
    },

    widgetComponents: {
       template: "...",
       components: components
    },

    widgetComponents2: {
       template: "...",
       components: components
    },

}

Есть ли узкое место в производительности при этом?

Вот почему я думаю, что может быть полезна «полуглобальная» область действия компонента. Это может помочь создавать приложения с закрытой областью компонентов, где компоненты будут доступны из корневых и дочерних компонентов. Но не от других корней vuejs. Что вы думаете?

Глобальная регистрация не регистрирует рекурсивно, она только регистрирует
сам компонент, а не те, что внутри его опции components . так что я думаю
не было проблемы.

В понедельник, 22 августа 2016 г., 16:00 Soufiane [email protected] написал:

@yyx990803 https://github.com/yyx990803 Я вижу конкретный вариант использования
Я как-то застрял.

_Что я пытаюсь сделать_

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

При загрузке виджет добавит динамически созданный компонент в
приложение vuejs.
Виджеты могут содержать другие виджеты (дочерние). Мы не знаем, как это
будет при запуске, потому что эта часть управляется пользователем после
приложение загружается. Вот почему виджеты должны знать друг о друге.

_Проблема_

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

переменные компоненты = {

appComponents: {
   template: "...",
   components: components
},

appComponents2: {
   template: "...",
   components: components
},

}

_Есть ли при этом узкое место в производительности?_


Вы получаете это, потому что подписаны на эту тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241339596 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AFTLl6QDePtH93VOU2lgrC72Z0vKLsv-ks5qiVcXgaJpZM4F7M1v
.

@fnlctrl Дело не в глобальной регистрации.

Проблема в том, что

  • глобальный регистр регистрации для всех экземпляров vue+component.
  • локальная регистрация регистрируется только для текущего компонента
  • и нет способа зарегистрироваться для root и дочерних элементов «полуглобально»: что-то, что позволяет зарегистрироваться для текущего экземпляра vue (включая компоненты, добавленные в этот экземпляр).

На мой взгляд, проблема в том, что vue хотя и предназначен для статического (глобального) способа, но он ограничен для упакованного/распространяемого (локального) способа.

Регистрация semi-global на самом деле уже возможна, поскольку Vue имеет прототипное наследование.
https://jsfiddle.net/fnlCtrl/32dt9e9g/

@fnlctrl
Я не уверен, что понимаю, что вы хотите показать с помощью отправленной вами скрипки (обратите внимание, что в вашем примере есть ошибка: Unknown custom element: <bar> - did you register the component correctly? )

Я недостаточно ясно выразился, возможно, вы не поняли, что я хочу объяснить. Давай начнем сначала:

Я хочу объяснить, что мы можем:

  • глобальные компоненты регистрации с Vue.component('name', {...}) (идеально подходит для одностраничного приложения)
  • Локально зарегистрировать компонент в компоненте new Vue({ components: {...} }); (хорошо поставлять компоненты с зависимостями для локального повторного использования)

Но мы не можем сделать доступными компоненты от родителя к дочерним. Что-то вроде глобальной регистрации компонентов для текущего экземпляра vm и всех компонентов, загруженных в этом экземпляре, но не для компонентов, загруженных в других экземплярах vm. См. пример: https://jsfiddle.net/p8wqafm1/2/

Ты понимаешь?

Ой, кажется, моя скрипка не была правильно сохранена..
Это то, что я хотел показать вам..
https://jsfiddle.net/fnlCtrl/32dt9e9g/1/

Я сейчас читаю ваш пример.

Я разветвил ваш пример здесь , который исправлен для работы, надеюсь, я вас правильно понял:
Вы хотите добавить динамические компоненты, ограниченные внутри Foo.

@fnlctrl Спасибо за ваш пример, но, похоже, он еще не охватывает того, чего я пытаюсь достичь.

Использование метода в вашем примере регистрирует компонент только в Foo , но это не делает их доступными в дочерних элементах Foo ( Bar в этом примере).

Посмотрите на скрипку, я регистрирую Baz в Foo , и я хотел бы, чтобы она была доступна в Bar , потому что она загружается из Foo : https://jsfiddle .net/8y0Lmb01/3/

Разветвил ваш пример: https://jsfiddle.net/fnlCtrl/uvzaotaz/

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

@fnlctrl В вашем примере Baz больше не доступен в Foo .

Для этого я мог бы использовать Vue.component('baz', {...} , но проблема в том, что он будет «загрязнять» другой экземпляр vue этим компонентом baz .

ИЛИ

Я мог бы зарегистрировать Baz как в Foo , так и Bar , и во всех дочерних элементах foo, и во всех дочерних элементах bar, и во всех Foo Grand Children и т. д. Но это добавляет большая сложность в случае большого/динамического приложения

Вы видите, что я имею в виду? Я могу зарегистрироваться локально, но мы не можем наследовать компоненты для детей, внуков,... текущих компонентов _only_

Да, теперь я понимаю вашу точку зрения. Извините, что я не знал, что регистрация
компонент под Foo не делает его глобальным внутри области действия Foo, в отличие от
Vue.компонент . Посмотрю в источник, чтобы понять, почему.

Пн, 22 августа 2016 г., 20:17 Суфиан Гхзаль, [email protected] написал:

@fnlctrl https://github.com/fnlctrl В вашем примере Баз недоступен
в Фу больше нет.

Для этого я мог бы использовать Vue.component('baz', {...}, но проблема в том, что
он будет «загрязнять» другой экземпляр vue этим базовым компонентом.

ИЛИ

Я мог бы зарегистрировать База и в Foo, и в Bar, и во всех foo дочерних элементах, и
все барные дети, и все Foo Grand Children, и т. д. Но это добавляет много
сложность в случае большого/динамического приложения

Вы видите, что я имею в виду? Я могу зарегистрироваться локально, но мы не можем наследовать
компоненты для детей, внуков,... текущих компонентов
_Только_


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Спасибо :)

Дело в том, что я хочу поставить автономную библиотеку, которая зависит от vue, регистрация компонентов для данного экземпляра будет реальной выгодой, потому что в любом случае, как автономная библиотека, мне не разрешено регистрировать это в глобальном экземпляре Vue ( это сломает отдельную часть).

Пожалуйста, дайте мне знать, может ли то, о чем я говорил, быть реализовано в Vue.

Что ж, думаю, причина была слишком очевидна, чтобы я ее не заметил: я не
используя new Foo() ...

Я получу скрипку через 20 минут по дороге домой.

В понедельник, 22 августа 2016 г., 20:27 宋铄运[email protected] написал:

Да, теперь я понимаю вашу точку зрения. Извините, что я не знал, что регистрация
компонент под Foo не делает его глобальным внутри области действия Foo, в отличие от
Vue.компонент . Посмотрю в источник, чтобы понять, почему.

Пн, 22 августа 2016 г., 20:17 Суфиан Гхзаль, уведомления@github.com
написал:

@fnlctrl https://github.com/fnlctrl В вашем примере База нет
доступны в Foo больше.

Для этого я мог бы использовать Vue.component('baz', {...}, но проблема в том, что
он будет «загрязнять» другой экземпляр vue этим базовым компонентом.

ИЛИ

Я мог бы зарегистрировать База и в Foo, и в Bar, и во всех foo дочерних элементах, и
все барные дети, и все Foo Grand Children, и т. д. Но это добавляет много
сложность в случае большого/динамического приложения

Вы видите, что я имею в виду? Я могу зарегистрироваться локально, но мы не можем наследовать
компоненты для детей, внуков,... текущих компонентов
_Только_


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Ну, new Foo(...) тоже не сработало: https://jsfiddle.net/8y0Lmb01/5/

Действительно странно... https://jsfiddle.net/fnlCtrl/p0ggkncu/
Глядя на это сейчас.

Я прочитал часть исходного кода и обнаружил, что на самом Vue мы можем взломать так:
https://jsfiddle.net/fnlCtrl/522aw9sm/
(без использования Vue.extend или Vue.component, кстати, Vue.component — это только вспомогательная функция, которая делает Vue.extend и изменяет Vue.options.components)

Хотя тот же подход не работает с расширенным Vue:
https://jsfiddle.net/fnlCtrl/v1m2s16u/

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

@fnlctrl Хорошо, спасибо, я попытался кое-что проверить и пришел к тому же выводу, что и вы. Я недостаточно знаю ядро, чтобы понять, почему это работает таким образом. Знаем ли мы, является ли это ожидаемым поведением?

Я думаю, что эти комментарии о resolveAsset

Разрешить актив.
Эта функция используется, потому что дочерним экземплярам нужен доступ
к активам, определенным в его цепочке предков.

предполагает, что регистрация компонентов в расширенном Vue должна работать.

Код в теле функции не смотрит на цепочку предков, верно? Может еще не реализовано?

Я еще недостаточно знаю, все еще изучаю его поведение, но я думаю, что «цепочка предков» относится к первому параметру options .

Думаю, я могу сделать вывод, что причина в этом (src/core/global-api/extend) .
Это заставляет расширенные классы использовать тот же метод, что и их родители.

Я проверил это, если вы скопируете то, что находится в core/global-api/assets (используйте соответствующий код внутри версии dist, которая, конечно, лишена типов)
в vue.extend, чтобы он выглядел так (измените Vue на Sub ):

config._assetTypes.forEach(function (type) {
        Sub[type] = function (id, definition) {
          if (!definition) {
            return this.options[type + 's'][id];
          } else {
            /* istanbul ignore if */
            if ("development" !== 'production') {
              if (type === 'component' && config.isReservedTag(id)) {
                warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + id);
              }
            }
            if (type === 'component' && isPlainObject(definition)) {
              definition.name = definition.name || id;
              definition = Sub.extend(definition);
            }
            if (type === 'directive' && typeof definition === 'function') {
              definition = { bind: definition, update: definition };
            }
            this.options[type + 's'][id] = definition;
            return definition;
          }
        };
      });

Foo = Vue.extend() и Foo.component() будут работать.

Хотя я предполагаю, что это приведет к некоторому снижению производительности.

@gsouf И я думаю, что нашел последнюю часть головоломки (эквивалентный обходной путь без изменения vue):
https://jsfiddle.net/fnlCtrl/v1m2s16u/

var Root = Vue.extend()

Root.options.components.Foo = Root.extend({
    template: '<div>Foo</div>'
})

Root.options.components.Bar = Root.extend({
    template: '<div>Bar, uses <foo></foo></div>'
})

new Root({
    template: `
  <div>
    <foo></foo>
    <bar></bar>
  </div>
  `
}).$mount('#app')

Привет @fnlctrl , спасибо за результат и извините за задержку.

Действительно похоже, что компоненты наследуют компоненты от их конструктора, а не от их родителя. В настоящее время ищу, могу ли я применить патч для моего варианта использования.

В вашем случае он остается привязанным к конструктору, а не к экземпляру, я ищу, чтобы он был только частью экземпляра

@fnlctrl из-за того, как работает javascript, и благодаря вашему примеру я мог обойти это, «динамически расширяя» vue для каждого создаваемого экземпляра, делая все доступным только для этого приложения.:

createVueInstance = function(el, data){
    var vExtend = Vue.extend();
    vExtend.partial('some-semiglobal-partial', "...");
    vExtend.component('some-semiglobal-component', vExtend.extend({...}));

    return new vExtend({
        el: el,
        data: data
    });
};

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

Спасибо за вашу помощь!

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

@gsouf Не за что. Думаю этого выпуска достаточно для тех, кто хочет реализовать подобную фичу :smile:

Здесь у меня есть «полуглобальный» вариант использования:

У меня есть относительно универсальный компонент макета, но содержимое настраивается компонентами, которые используют компонент макета, например. компонент A использует макет и хочет настроить свое содержимое с помощью компонента B, какой-то другой компонент может использовать макет и настроить свое содержимое с помощью компонента C и т. д.

Должен ли этот шаблон поддерживаться?

Или есть какое-то решение, чтобы заменить эту конструкцию?

Шаблон широко используется в iOS для улучшения повторного использования кода, и это гибкий дизайн.

@hpsoar Что вам, вероятно, нужно, так это слоты

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

  1. простая настройка ячейки с помощью стиля css, которого будет достаточно во многих случаях;
  2. вставьте в ячейку компонент, который будет использоваться для особых случаев.
<template>
  <div class="tile is-ancestor">
    <div class="tile is-parent">
      <article class="tile is-child box">
        <div class="table-responsive">
          <table class="table is-bordered is-striped is-narrow">
            <thead>
            <tr>
              <th v-for="c in columns">
                {{c.title}}
              </th>
            </tr>
            </thead>
            <tbody>
            <tr v-for="(item, index) in items">
              <template v-for="c in columns">
                <td v-if="c.hasOwnProperty('component')"><div :is="c.component"></div></td>
                <td v-else>{{ item[c.name] }}</td>
              </template>
            </tr>
            </tbody>
          </table>
        </div>
      </article>
    </div>
  </div>
</template>

<script>

export default {
  components: {
  },
  props: [
    'columns',
    'items'
  ],
  data: function () {
    return {
    }
  }
}

</script>

<style lang="scss" rel="stylesheet/scss">
  .table-responsive {
    display: block;
    width: 100%;
    min-height: .01%;
    overflow-x: auto;
  }
</style>

Была ли эта страница полезной?
0 / 5 - 0 рейтинги