Vue: Permita que los niños "hereden" componentes registrados para los padres.

Creado en 10 sept. 2015  ·  36Comentarios  ·  Fuente: vuejs/vue

Creo que esta función se eliminó intencionalmente, pero en algunos casos puede ser muy útil. ¿Por qué no volver a poner esto probablemente haciéndolo opcional?

Comentario más útil

Importarlos explícitamente es una repetición que vale la pena. Le permite observar cualquier componente en esa jerarquía solo y comprender de dónde provienen sus dependencias. Con el respaldo implícito, no recordará dónde importó esos componentes en la jerarquía 3 meses después.

Todos 36 comentarios

¿Algún caso de uso en el mundo real?

En casos de uso pequeños, simplemente registre todo globalmente; en aplicaciones grandes, es mucho más mantenible que cada componente dependa explícitamente de lo que necesita. Puede ser útil en algunas situaciones, pero los beneficios vienen con una compensación global. La idea detrás de 1.0 es que "si algo es solo marginalmente útil o tiene implicaciones negativas en la mantenibilidad, eliminémoslo".

Sí. Mi aplicación tiene una ventana emergente que tiene una estructura compleja de elementos de edición personalizados. Estos elementos se pueden combinar en una jerarquía de 3 o 4 niveles, lo que hace que sea ineficiente declararlos explícitamente para cada elemento principal (3 a 5 tipos principales * 10 elementos declarados = 50 líneas de código repetitivo). Y tampoco es bueno registrarlos globalmente ya que nunca aparecerán en otras partes de la aplicación. Así que me encantaría tenerlos cargados "localmente".

Importarlos explícitamente es una repetición que vale la pena. Le permite observar cualquier componente en esa jerarquía solo y comprender de dónde provienen sus dependencias. Con el respaldo implícito, no recordará dónde importó esos componentes en la jerarquía 3 meses después.

@yyx990803 Tengo buena memoria, gracias. Así que recordaré que mi aplicación consta de dos piezas muy diferentes, cada una de las cuales registra un conjunto bien definido de componentes específicos. Por lo tanto, preferiría poder elegir dónde cargar mis activos (y sospecho que sucedió lo mismo con las directivas y filtros personalizados).

Déjame compartir mi impresión. Trabajé con 0.12.x y funcionó MUY bien (menos algunas cosas menores de la curva de aprendizaje). API minimalista y limpia, sintaxis, código confiable. Ahora, estamos en 1.0.0-beta y empeoró, no mejoró. Más repetición de código, las características que uso eliminadas me obligan a reescribir el mismo código una y otra vez. Estoy empezando a pensar que cometí un error al elegir Vue en lugar de React, porque no estoy seguro de que no haya más cambios importantes y pérdida de tiempo en el futuro.

@karevn

  1. Sería mucho más útil si enumerara las cosas específicas que empeoraron la experiencia del desarrollador además de este problema.
  2. 1.0.0-alpha son versiones preliminares, lo que significa que, en primer lugar, no había ninguna garantía de estabilidad de la API. Si valora la estabilidad, debe ceñirse a 0.12 y esperar a la versión estable 1.0 (que también tendrá una versión de migración final). El uso de un prelanzamiento significa que ha aceptado lidiar con cambios de última hora constantes.
  3. 1.0.0-beta ni siquiera se lanza. Probablemente no sea una buena idea usar una rama de trabajo en progreso que no se haya publicado.
  4. Estoy diseñando la API según mi experiencia y los comentarios de toda la comunidad. Tienes derecho a lo que pienses, y siéntete libre de cambiar a otros marcos si los cambios no van en la dirección que te gusta. (De hecho, en React también tienes que importar todo explícitamente y tendrás que repetir aún más cosas).
  1. Después de leer la discusión #1170, ahora estoy casi de acuerdo. Pero... Realmente no veo el punto de eliminar el código existente que proporcionó esta función en lugar de simplemente hacer que strict: true sea ​​el valor predeterminado. Los gustos difieren, y algunas personas preferirán tener un enfoque "alternativo", que a veces es más intuitivo. Especialmente, cuando los componentes se cargan dinámicamente. Se puede solucionar con mixins, fábricas, etc., pero todo lleva un tiempo precioso.
  2. Cosa segura. Pero siempre hay un equilibrio entre la "arquitectura ideal" y el costo de los cambios. En este caso, unas pocas líneas de código (a saber: alrededor de 10) que no dañarían a nadie si se dejaran me costaron mucho tiempo. Y tengo que usar esta versión inestable ya que realmente necesito la función de "filtros de enlace de lectura y escritura" que probablemente no se retrotraerán a 0.12.x
  3. Ver 2.
  4. La pregunta no es "qué API prefiero". Prefiero Vue. Período. La pregunta es "si puedo confiar en la API de Vue a largo plazo". Confiabilidad sobre hermosura. Si los cambios se están rompiendo, debe haber una razón seria para ellos. En el caso de la nueva sintaxis de enlace, que rompió TODO mi código, está bien, déjalo ser, es más legible y fuerza una mejor estructura de código. En este caso, no. Este cambio podría no interrumpirse con options.strict = true establecido de manera predeterminada.

Sí, la actualización siempre viene con el dolor de la refactorización, pero 1.0 es la única oportunidad para que Vue se libere de estas opciones de configuración heredadas. Después de 1.0 será estrictamente sever, y nada debería fallar hasta 2.0. Y quiero que 1.x dure el mayor tiempo posible, debido al problema de confiabilidad del que hablaste.

Con respecto al modo estricto: seguramente cuesta tiempo de refactorización cuando ha confiado mucho en él, pero idealmente para los nuevos usuarios que adquieren Vue después de 1.0, ni siquiera necesitan saber que existe. La superficie de la API debe ser lo más pequeña posible y el patrón de estructuración global debe ser lo más consistente posible. Hacer posible deshabilitar el modo estricto esencialmente fomenta dos estilos diferentes de estructuración de aplicaciones Vue: imagina a las personas que trabajan en una aplicación que usa strict: true y luego se mueven a otro proyecto que usa strict: false ... crea fragmentación de la experiencia del desarrollador, y quiero deshacerme de esa posibilidad, y 1.0 es el único lugar razonable para hacerlo.

Es un poco desafortunado para ti quedar atrapado en medio de esta transición, y agradezco tus comentarios. Pero lo que hay que hacer hay que hacerlo.

@ yyx990803 Puedo ver un caso de uso concreto con el que estoy atascado.

lo que estoy tratando de hacer

Construyo una aplicación extensible: extensible con widgets. Un widget es una pieza definida por el desarrollador de la aplicación que conecta la aplicación global para extenderla en algunos puntos; se carga dinámicamente al inicio de la aplicación. Cada instancia de la aplicación puede tener un conjunto diferente de widgets y 2 instancias de la aplicación pueden vivir en la misma página.

Cuando se carga, el widget agregará un componente creado dinámicamente a la aplicación vuejs.
Los widgets pueden contener otros widgets (hijos). No sabemos cómo será en el inicio porque el usuario administra esta parte después de cargar la aplicación. Es por eso que los widgets deben conocerse entre sí y registrar otros widgets.

El problema

Quiero evitar registrar estos widgets globalmente (razones de compatibilidad).
Debido a que los componentes se construyen y cargan dinámicamente, necesito registrar todos los componentes en cada componente que pueda contener elementos secundarios. Eso hace mucho registro que podría no usarse. Vea lo que quiero decir (tenga en cuenta que por el momento no probé el registro local de componentes, haciendo las pruebas con registro global):

var components = {

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

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

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

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

}

¿Hay un cuello de botella en el rendimiento al hacer esto?

Es por eso que creo que el alcance de un componente "semi global" podría ser útil. Podría ayudar a crear aplicaciones con un alcance cerrado de componente donde los componentes serán accesibles desde los componentes raíz y secundarios. Pero no de otras raíces vuejs. ¿Qué piensas?

El registro global no registra recursivamente, solo registra el
componente en sí mismo y no los que están dentro de su opción components . así que supongo
no hubo problema

El lunes 22 de agosto de 2016 a las 16:00, Soufiane Ghzal [email protected] escribió:

@ yyx990803 https://github.com/yyx990803 Puedo ver un caso de uso concreto
Estoy un poco atascado.

_Lo que estoy tratando de hacer_

Construyo una aplicación extensible: extensible con widgets. Un widget es un
pieza definida por el desarrollador de la aplicación, se carga dinámicamente en el
puesta en marcha de la aplicación. Cada instancia de la aplicación puede tener
conjunto diferente de widgets.

Cuando se carga, el widget agregará un componente creado dinámicamente al
aplicación vuejs.
Los widgets pueden contener otros widgets (hijos). No sabemos cómo
estará en el inicio porque esta parte es administrada por el usuario después
se carga la aplicación. Es por eso que los widgets deben conocerse entre sí.

_El problema_

Quiero evitar registrar estos widgets globalmente.
Debido a que los widgets se cargan dinámicamente, necesito registrar todos los widgets en
cada widget que puede contener niños. Eso hace mucho para registrar eso
puede que no se use. Ver:

var componentes = {

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

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

}

_¿Hay un cuello de botella en el rendimiento al hacer esto?_


Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241339596, o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AFTLl6QDePtH93VOU2lgrC72Z0vKLsv-ks5qiVcXgaJpZM4F7M1v
.

@fnlctrl No se trata de un registro global.

El problema es ese

  • registro de registro global para todas las instancias de vue+component.
  • registros de registro locales solo para el componente actual
  • y no hay forma de registrarse para la raíz y los niños "semi global": algo que permite registrarse para la instancia actual de vue (incluidos los componentes agregados a esta instancia también).

En mi opinión, el problema es que vue está pensado para la forma estática (global), pero está restringido para la forma empaquetada/distribuible (local).

El registro semi-global ya es posible ya que Vue tiene herencia prototípica.
https://jsfiddle.net/fnlCtrl/32dt9e9g/

@fnlctrl
No estoy seguro de entender lo que quiere mostrar con el violín que envió (tenga en cuenta que su ejemplo tiene un error: Unknown custom element: <bar> - did you register the component correctly? )

No soy lo suficientemente claro, tal vez no entendiste lo que quiero explicar. Vamos a empezar de nuevo:

Lo que quiero explicar es que podemos:

  • registrar componentes globalmente con Vue.component('name', {...}) (eso es perfecto para la aplicación de una sola página)
  • Registre localmente un componente en un componente new Vue({ components: {...} }); (eso es bueno para enviar componentes con dependencias para la reutilización local)

Pero no podemos hacer que los componentes estén disponibles del padre a los hijos. Algo así como registrar globalmente los componentes para la instancia actual vm y todos los componentes cargados en esta instancia, pero no para los componentes cargados en otras instancias de vm. Vea el ejemplo: https://jsfiddle.net/p8wqafm1/2/

Lo entiendes?

Vaya, parece que mi violín no se guardó correctamente ...
Este es el que te quería mostrar..
https://jsfiddle.net/fnlCtrl/32dt9e9g/1/

Estoy leyendo tu ejemplo ahora mismo.

He bifurcado tu ejemplo aquí que está corregido para que funcione, espero haberte entendido correctamente:
Desea agregar componentes dinámicos limitados dentro de Foo.

@fnlctrl Gracias por su ejemplo, pero parece que aún no cubre lo que estoy tratando de lograr.

El uso del método en su ejemplo registra el componente en Foo solo, pero eso no los hace disponibles en los elementos secundarios de Foo ( Bar en este ejemplo).

Mira el violín, registro Baz en Foo y me gustaría que esté disponible en Bar porque se carga desde Foo : https://jsfiddle .net/8y0Lmb01/3/

Bifurcó su ejemplo: https://jsfiddle.net/fnlCtrl/uvzaotaz/

El punto es que los componentes deben tener un árbol de dependencia claro, y los componentes dinámicos que dependen unos de otros no deberían ser una excepción.

@fnlctrl En su ejemplo, Baz ya no está disponible en Foo .

Para hacerlo, podría usar Vue.component('baz', {...} pero el problema es que "contaminará" otra instancia de vue con este componente baz .

O

Podría registrar Baz tanto en Foo como en Bar , y todos los niños foo, y todos los niños del bar, y todos los niños Foo Grand, etc. Pero eso agrega un mucha complejidad en el caso de una aplicación grande/dinámica

¿Ves lo que quiero decir? Puedo registrarme localmente, pero no podemos heredar componentes para los hijos, nietos,... de los componentes actuales _solo_

Sí, ahora veo tu punto. Lo siento, no sabía que registrarme
El componente bajo Foo no lo hace global dentro del alcance de Foo, a diferencia de
Vue.componente. Buscará en la fuente para ver por qué.

El lunes, 22 de agosto de 2016, 20:17, Soufiane Ghzal [email protected] escribió:

@fnlctrl https://github.com/fnlctrl En tu ejemplo, Baz no está disponible
en Foo nunca más.

Para hacerlo podría usar Vue.component('baz', {...} pero el problema es que
"contaminará" otra instancia de vue con este componente baz.

O

Podría registrar a Baz tanto en Foo como en Bar, y en todos los niños foo, y
todos los bar children, y todos los Foo Grand Children, etc... Pero eso agrega mucho
complejidad en el caso de una aplicación grande/dinámica

¿Ves lo que quiero decir? Puedo registrarme localmente, pero no podemos heredar
componentes para los hijos, nietos,... de los componentes actuales
_solo_


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119, o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Gracias :)

El punto es que quiero enviar una biblioteca independiente que dependa de vue, el registro de componentes para instancias determinadas será un beneficio real, porque de todos modos, como biblioteca independiente, no puedo registrar eso en la instancia global de Vue ( eso rompería la parte independiente).

Por favor, hágame saber si lo que estaba hablando podría implementarse en Vue.

Bueno, supongo que la razón era demasiado obvia como para pasarla por alto: no estaba
usando new Foo() ...

Conseguiré un violín en 20 minutos, de camino a casa.

El lunes 22 de agosto de 2016 a las 20:27 宋铄运[email protected] escribió:

Sí, ahora veo tu punto. Lo siento, no sabía que registrarme
El componente bajo Foo no lo hace global dentro del alcance de Foo, a diferencia de
Vue.componente. Buscará en la fuente para ver por qué.

El lunes 22 de agosto de 2016 a las 20:17 Soufiane Ghzal [email protected]
escribió:

@fnlctrl https://github.com/fnlctrl En tu ejemplo, Baz no es
disponible en Foo más.

Para hacerlo podría usar Vue.component('baz', {...} pero el problema es que
"contaminará" otra instancia de vue con este componente baz.

O

Podría registrar a Baz tanto en Foo como en Bar, y en todos los niños foo, y
todos los bar children, y todos los Foo Grand Children, etc... Pero eso agrega mucho
complejidad en el caso de una aplicación grande/dinámica

¿Ves lo que quiero decir? Puedo registrarme localmente, pero no podemos heredar
componentes para los hijos, nietos,... de los componentes actuales
_solo_


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119, o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Bueno, new Foo(...) tampoco funcionó: https://jsfiddle.net/8y0Lmb01/5/

De hecho extraño... https://jsfiddle.net/fnlCtrl/p0ggkncu/
Mirándolo ahora.

Leí parte del código fuente y descubrí que en Vue, podemos piratear así:
https://jsfiddle.net/fnlCtrl/522aw9sm/
(sin usar Vue.extend o Vue.component, por cierto, Vue.component es solo una función auxiliar que hace Vue.extend y modifica Vue.options.components)

Aunque el mismo enfoque no funciona en un Vue extendido:
https://jsfiddle.net/fnlCtrl/v1m2s16u/

Así que supongo que el problema es causado por la resolución de componentes. Seguiré buscando.

@fnlctrl Ok, gracias, intenté verificar algunas cosas y llegué a la misma conclusión que la tuya. No sé el núcleo lo suficiente como para saber por qué funciona de esta manera. ¿Sabemos si es el comportamiento esperado?

Creo que estos comentarios sobre resolveAsset

Resolver un activo.
Esta función se usa porque las instancias secundarias necesitan acceso
a los activos definidos en su cadena antecesora.

sugiere que se supone que el registro de componentes en Vue extendido funciona.

El código en el cuerpo de la función no mira la cadena principal, ¿verdad? ¿Quizás aún no se implementó?

Todavía no sé lo suficiente, sigo aprendiendo su comportamiento, pero supongo que la "cadena de antepasados" se refiere al primer parámetro options .

Supongo que puedo concluir que la causa es esta (src/core/global-api/extend) .
Hace que las clases extendidas utilicen el mismo método de sus padres.

Lo probé, si copia lo que hay en core/global-api/assets (use el código correspondiente dentro de la versión dist que está despojada de tipos, por supuesto)
a vue.extend, para que se vea así (cambie Vue a 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;
          }
        };
      });

los Foo = Vue.extend() y Foo.component() funcionarán.

Aunque supongo que esto causará alguna penalización en el rendimiento.

@gsouf Y creo que encontré la última pieza del rompecabezas (una solución equivalente sin modificar 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')

Hola @fnlctrl , gracias por el resultado y perdón por la demora.

De hecho, parece que los componentes heredan componentes de su constructor, no de su padre. Actualmente estoy buscando si puedo aplicar un parche para mi caso de uso.

En su caso, permanece adjunto a un constructor, no a una instancia, estoy buscando que sea solo parte de la instancia

@fnlctrl debido a la forma en que funciona javascript y, gracias a su ejemplo, pude solucionarlo "extendiendo dinámicamente" vue para cada instancia que creo, haciendo que todo esté disponible solo para esta aplicación:

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
    });
};

Después de verificar cómo se construyó el núcleo, no parece que se haya construido para permitir una fácil integración de los componentes disponibles por instancia y esta solución es lo suficientemente estable para mí.

¡Gracias por tu ayuda!

Por cierto, creo que el ejemplo que me mostraste podría explicarse profundamente en el documento. no encontre mencion al respecto

@gsouf De

Aquí tengo un caso de uso 'semi-global':

Tengo un componente de diseño relativamente universal, pero el contenido es configurable por los componentes que usan el componente de diseño, por ejemplo. el componente A usa Layout y desea configurar su contenido con el componente B, algún otro componente puede usar Layout y configurar su contenido con el componente C, etc.

¿Debería admitirse este patrón?

¿O hay alguna solución para reemplazar este diseño?

El patrón se usa ampliamente en iOS para mejorar la reutilización de código y este es un diseño flexible.

@hpsoar Lo que probablemente necesites son tragamonedas

Mi Diseño es el siguiente, básicamente esto me permitirá hacer dos cosas con el celular:

  1. simplemente configure la celda con un estilo css, que será suficiente para muchos casos;
  2. inserte un componente en la celda, que se utilizará para casos especiales.
<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>

¿Fue útil esta página
0 / 5 - 0 calificaciones