Vue: Permitir que os filhos "herdem" componentes registrados para os pais.

Criado em 10 set. 2015  ·  36Comentários  ·  Fonte: vuejs/vue

Acho que esse recurso foi removido intencionalmente, mas em alguns casos pode ser muito útil. Por que não colocar essa coisa de volta provavelmente tornando-a opcional?

Comentários muito úteis

Importá-los explicitamente é uma repetição que vale a pena. Ele permite que você veja qualquer componente nessa hierarquia sozinho e entenda de onde vêm suas dependências. Com o fallback implícito, você não se lembrará de onde importou esses componentes na hierarquia 3 meses depois.

Todos 36 comentários

Algum caso de uso do mundo real?

Em casos de uso pequenos, basta registrar tudo globalmente; em aplicativos grandes, é muito mais fácil de manter para cada componente depender explicitamente do que ele precisa. Pode ser útil em algumas situações, mas os benefícios vêm com uma compensação global. A ideia por trás do 1.0 é que "se algo é apenas marginalmente útil, ou tem implicações negativas na manutenção, vamos removê-lo".

Sim. Meu aplicativo tem uma janela pop-up com uma estrutura complexa de elementos de editor personalizados. Esses elementos podem ser combinados em uma hierarquia de 3-4 níveis, tornando ineficiente declará-los explicitamente para cada elemento pai (3-5 tipos pai * 10 elementos declarados = 50 linhas de código repetido). E também não é bom registrá-los globalmente, pois eles nunca aparecerão em outras partes do aplicativo. Então, eu adoraria tê-los carregados "localmente".

Importá-los explicitamente é uma repetição que vale a pena. Ele permite que você veja qualquer componente nessa hierarquia sozinho e entenda de onde vêm suas dependências. Com o fallback implícito, você não se lembrará de onde importou esses componentes na hierarquia 3 meses depois.

@yyx990803 Eu tenho uma boa memória, obrigado. Então vou lembrar que meu aplicativo é composto por duas peças bem diferentes, cada uma delas registrando um conjunto bem definido de componentes específicos para ela. Então, eu preferiria ter a opção de onde carregar meus ativos (e suspeito que a mesma coisa aconteceu com diretivas e filtros personalizados).

Deixe-me compartilhar minha impressão. Eu trabalhei com 0.12.xe correu MUITO bem (menos algumas pequenas coisas de curva de aprendizado). API minimalista e limpa, sintaxe, código confiável. Agora, estamos em 1.0.0-beta e ficou PIOR, não melhor. Mais repetição de código, recursos que eu uso foram removidos, me fazendo reescrever o mesmo código várias vezes. Estou começando a pensar que cometi um erro ao escolher Vue em vez de React, porque não tenho certeza de que não haverá mais mudanças de última hora e perda de tempo no futuro.

@karevn

  1. Seria muito mais útil se você realmente listasse as coisas específicas que pioraram a experiência do desenvolvedor além desse problema.
  2. 1.0.0-alpha são pré-lançamentos, o que significa que não havia garantia de estabilidade da API em primeiro lugar. Se você valoriza a estabilidade, deve manter a versão 0.12 e aguardar a versão estável 1.0 (que também terá uma versão final da migração). Usar um pré-lançamento significa que você concordou em lidar com mudanças constantes.
  3. 1.0.0-beta nem foi lançado. Provavelmente não é uma boa ideia usar uma ramificação não lançada e em andamento.
  4. Estou projetando a API com base na minha experiência e feedback de toda a comunidade. Você tem direito a tudo o que pensa e sinta-se à vontade para mudar para outras estruturas se as mudanças não estiverem na direção que você gosta. (Na verdade, no React você também tem que importar tudo explicitamente e terá que repetir ainda mais coisas.)
  1. Depois de ler a discussão #1170 estou quase de acordo agora. Mas .. Eu realmente não vejo sentido em remover o código existente que fornece esse recurso em vez de apenas tornar strict: true o padrão. Os gostos diferem e algumas pessoas preferem ter uma abordagem de "retorno", que às vezes é mais intuitiva. Especialmente, quando os componentes são carregados dinamicamente. Pode ser trabalhado com mixins, fábricas, etc, mas tudo leva um tempo precioso.
  2. Coisa certa. Mas sempre há um equilíbrio entre a "arquitetura ideal" e o custo das mudanças. Neste caso, algumas linhas de código (a saber: cerca de 10) que não fariam mal a ninguém se fossem deixadas me custaram um tempo significativo. E eu tenho que usar esta versão instável, pois realmente preciso do recurso "filtros de ligação de leitura e gravação", que provavelmente não serão portados para 0.12.x
  3. Veja 2.
  4. A questão não é "qual API eu prefiro". Prefiro Vue. Período. A questão é "se posso confiar na API Vue a longo prazo". Confiabilidade sobre beleza. Se as mudanças estão quebrando, deve haver uma razão séria para elas. No caso da nova sintaxe de ligação, que quebrou TODO o meu código - ok, deixe estar, é mais legível e força uma melhor estrutura de código. Neste caso - não. Essa alteração pode ser ininterrupta com options.strict = true definido por padrão.

Sim, a atualização sempre vem com a dor da refatoração, mas 1.0 é a única chance do Vue se libertar dessas opções de configuração herdadas. Após 1.0, será estritamente semver, e nada deve quebrar até 2.0. E eu quero que 1.x dure o máximo possível, por causa do problema de confiabilidade que você falou.

Em relação ao modo estrito: certamente custa tempo de refatoração quando você confia muito nele - mas idealmente para novos usuários que pegam Vue após 1.0, eles nem precisam saber que essa coisa existe. A superfície da API deve ser a menor possível e o padrão de estruturação global deve ser o mais consistente possível. Tornar possível desabilitar o modo estrito basicamente encoraja dois estilos diferentes de estruturar aplicativos Vue - imagine pessoas trabalhando em um aplicativo que usa strict: true , depois movendo para outro projeto que usa strict: false ... fragmentação da experiência do desenvolvedor, e eu quero me livrar dessa possibilidade, e 1.0 é o único lugar razoável para fazer isso.

É meio azarado você ser pego no meio dessa transição, e agradeço seu feedback. Mas o que precisa ser feito tem que ser feito.

@yyx990803 Posso ver um caso de uso concreto com o qual estou preso.

O que estou tentando fazer

Eu construo um aplicativo extensível: extensível com widgets. Um widget é uma parte do aplicativo definida pelo desenvolvedor que conecta o aplicativo global para estendê-lo em alguns pontos; ele é carregado dinamicamente na inicialização do aplicativo. Cada instância do aplicativo pode ter um conjunto diferente de widgets e 2 instâncias do aplicativo podem estar na mesma página.

Quando carregado, o widget adicionará um componente criado dinamicamente ao aplicativo vuejs.
Widgets podem conter outros widgets (filhos)., não sabemos como será na inicialização porque essa parte é gerenciada pelo usuário após o carregamento da aplicação. É por isso que os widgets precisam estar cientes uns dos outros e registrar outros widgets.

O problema

Eu quero evitar registrar esses widgets globalmente (motivos de compatibilidade).
Como os componentes são construídos e carregados dinamicamente, preciso registrar todos os componentes em cada componente que pode conter filhos. Isso faz um monte de registro que pode não ser usado. Veja o que quero dizer (observe que no momento não tentei registro local de componentes, fazendo os testes com registro global):

var components = {

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

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

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

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

}

Existe um gargalo de desempenho ao fazer isso?

É por isso que acho que o escopo de um componente "semi global" pode ser útil. Pode ajudar a construir aplicativos com um escopo fechado de componentes onde os componentes serão acessíveis a partir de componentes raiz e filhos. Mas não de outras raízes vuejs. O que você acha?

O registro global não se registra recursivamente, apenas registra o
componente em si e não aqueles dentro dele é a opção components . então eu acho
não houve problema.

Em segunda-feira, 22 de agosto de 2016, 16:00 Soufiane Ghzal [email protected] escreveu:

@yyx990803 https://github.com/yyx990803 Posso ver um caso de uso concreto
Estou meio preso.

_O que estou tentando fazer_

Eu construo um aplicativo extensível: extensível com widgets. Um widget é um
parte do aplicativo definida pelo desenvolvedor, ele é carregado dinamicamente no
inicialização do aplicativo. Cada instância do aplicativo pode ter
conjunto diferente de widgets.

Quando carregado, o widget adicionará um componente criado dinamicamente ao
aplicativo vuejs.
Widgets podem conter outros widgets (filhos)., não sabemos como
estará na inicialização porque esta parte é gerenciada pelo usuário após
aplicativo é carregado. É por isso que os widgets precisam estar cientes uns dos outros.

_O problema_

Eu quero evitar registrar esses widgets globalmente.
Como os widgets são carregados dinamicamente, preciso registrar todos os widgets no
cada widget que pode conter filhos. Isso registra muito isso
pode não ser usado. Ver:

var componentes = {

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

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

}

_Existe um gargalo de desempenho ao fazer isso?_


Você está recebendo isso porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241339596, ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AFTLl6QDePtH93VOU2lgrC72Z0vKLsv-ks5qiVcXgaJpZM4F7M1v
.

@fnlctrl Não se trata de registro global.

O problema é que

  • registro de registro global para todas as instâncias do vue+component.
  • registros de registro local apenas para o componente atual
  • e não há como registrar para root e child "semi global": algo que permita registrar para a instância vue atual (incluindo os componentes adicionados a esta instância também).

Na minha opinião, o problema é que o vue é para o modo estático (global), mas é restrito para o modo empacotado/distribuível (local).

O registro semi-global na verdade já é possível já que o Vue tem herança prototípica.
https://jsfiddle.net/fnlCtrl/32dt9e9g/

@fnlctrl
Não tenho certeza de entender o que você quer mostrar com o violino que você enviou (observe que seu exemplo tem erro: Unknown custom element: <bar> - did you register the component correctly? )

Não fui claro o suficiente, talvez você não tenha entendido o que quero explicar. Vamos começar novamente:

O que eu quero explicar é que podemos:

  • registre globalmente componentes com Vue.component('name', {...}) (que é perfeito para aplicativos de página única)
  • Registre localmente um componente em um componente new Vue({ components: {...} }); (é bom enviar componentes com dependências para reutilização local)

Mas não podemos disponibilizar componentes do pai para os filhos. Algo como registrar globalmente componentes para a instância vm atual e todos os componentes carregados nesta instância, mas não para componentes carregados em outras instâncias vm. Veja o exemplo: https://jsfiddle.net/p8wqafm1/2/

Voce entende?

Ops, parece que meu violino não foi salvo corretamente..
Este é o que eu pretendia mostrar a você..
https://jsfiddle.net/fnlCtrl/32dt9e9g/1/

Estou lendo seu exemplo agora.

Eu bifurquei seu exemplo aqui que está corrigido para funcionar, espero ter entendido corretamente:
Você deseja adicionar componentes dinâmicos limitados dentro do Foo.

@fnlctrl Obrigado pelo seu exemplo, mas parece que ainda não cobre o que estou tentando alcançar.

Usar o método em seu exemplo registra o componente em Foo apenas, mas isso não os disponibiliza nos filhos de Foo ( Bar neste exemplo).

Veja o violino, cadastrei Baz em Foo e gostaria que estivesse disponível em Bar porque está carregado a partir de Foo : https://jsfiddle .net/8y0Lmb01/3/

Bifurcou seu exemplo: https://jsfiddle.net/fnlCtrl/uvzaotaz/

O ponto é que os componentes devem ter uma árvore de dependência clara, e os componentes dinâmicos que dependem uns dos outros não devem ser uma exceção.

@fnlctrl No seu exemplo Baz não está mais disponível em Foo .

Para fazer isso, eu poderia usar Vue.component('baz', {...} mas o problema é que ele "poluirá" outra instância do vue com esse componente baz .

OU

Eu poderia registrar Baz em ambos Foo e Bar , e todos os foo children, e todos os bar children, e todos os Foo Grand Children, etc... muita complexidade no caso de aplicativo grande/dinâmico

Você vê o que quero dizer? Posso registrar localmente, mas não podemos herdar componentes para os filhos, netos,... dos componentes atuais _somente_

Sim, eu vejo seu ponto agora. Desculpe, eu não sabia que o registro
componente sob Foo não o torna global dentro do escopo de Foo, ao contrário
Vue.component . Vai olhar para a fonte para ver o porquê.

Em segunda-feira, 22 de agosto de 2016, 20:17 Soufiane Ghzal [email protected] escreveu:

@fnlctrl https://github.com/fnlctrl No seu exemplo Baz não está disponível
em Foo mais.

Para fazer isso eu poderia usar Vue.component('baz', {...} mas o problema é que
ele "poluirá" outra instância vue com este componente baz.

OU

Eu poderia registrar Baz tanto no Foo quanto no Bar, e em todos os foo children, e
todos os filhos do bar, e todos os Foo Grand Children, etc...
complexidade no caso de aplicativo grande/dinâmico

Você vê o que quero dizer? Posso me registrar localmente, mas não podemos herdar
componentes para os filhos, netos,... dos componentes atuais
_só_


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119, ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Obrigado :)

O ponto é que eu quero enviar uma biblioteca autônoma que depende do vue, registrar componentes para uma determinada instância será um benefício real, porque de qualquer maneira, como uma biblioteca autônoma, não tenho permissão para registrar isso na instância global do Vue ( que quebraria a parte autônoma).

Por favor, deixe-me saber se o que eu estava falando pode ser implementado no Vue

Bem, eu acho que a razão era muito óbvia que eu ignoro: eu não estava
usando new Foo() ...

Vai pegar um violino em 20min, na minha volta para casa.

Em seg, 22 de agosto de 2016, 20:27 宋铄运[email protected] escreveu:

Sim, eu vejo seu ponto agora. Desculpe, eu não sabia que o registro
componente sob Foo não o torna global dentro do escopo de Foo, ao contrário
Vue.component . Vai olhar para a fonte para ver o porquê.

Em segunda-feira, 22 de agosto de 2016, 20:17 Soufiane Ghzal [email protected]
escreveu:

@fnlctrl https://github.com/fnlctrl No seu exemplo, Baz não é
disponível em Foo mais.

Para fazer isso eu poderia usar Vue.component('baz', {...} mas o problema é que
ele "poluirá" outra instância vue com este componente baz.

OU

Eu poderia registrar Baz tanto no Foo quanto no Bar, e em todos os foo children, e
todos os filhos do bar, e todos os Foo Grand Children, etc...
complexidade no caso de aplicativo grande/dinâmico

Você vê o que quero dizer? Posso me registrar localmente, mas não podemos herdar
componentes para os filhos, netos,... dos componentes atuais
_só_


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/vuejs/vue/issues/1297#issuecomment -241395119, ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AFTLl2ud0GDO_hOwFN8GIA1TzVEF1q0Fks5qiZM9gaJpZM4F7M1v
.

Bem, new Foo(...) também não funcionou: https://jsfiddle.net/8y0Lmb01/5/

Estranho mesmo... https://jsfiddle.net/fnlCtrl/p0ggkncu/
Olhando para ele agora.

Eu li parte do código-fonte e descobri que no próprio Vue, podemos hackear assim:
https://jsfiddle.net/fnlCtrl/522aw9sm/
(sem usar Vue.extend ou Vue.component, Vue.component é apenas uma função auxiliar que faz Vue.extend e modifica Vue.options.components)

Embora a mesma abordagem não funcione em um Vue estendido:
https://jsfiddle.net/fnlCtrl/v1m2s16u/

Então, suponho que o problema seja causado pela resolução dos componentes. Vou continuar procurando.

@fnlctrl Ok obrigado, tentei verificar algumas coisas e cheguei à mesma conclusão que a sua. Eu não conheço o núcleo o suficiente para descobrir por que ele funciona dessa maneira. Sabemos se é o comportamento esperado?

Acho que esses comentários sobre resolveAsset

Resolver um ativo.
Esta função é usada porque as instâncias filhas precisam de acesso
aos ativos definidos em sua cadeia ancestral.

sugere que registrar componentes no Vue estendido deve funcionar.

O código no corpo da função não olha para a cadeia ancestral, certo? Talvez ainda não tenha sido implementado?

Ainda não sei o suficiente, ainda estou aprendendo seu comportamento, mas acho que a "cadeia ancestral" se refere ao primeiro parâmetro options .

Acho que posso concluir que a causa é essa (src/core/global-api/extend) .
Isso faz com que as classes estendidas usem o mesmo método de seus pais.

Eu testei isso, se você copiar o que está em core/global-api/assets (use o código correspondente dentro da versão dist que é despojada de tipos, é claro)
para vue.extend, para ficar assim (altere Vue para 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;
          }
        };
      });

os Foo = Vue.extend() e Foo.component() funcionarão.

Embora eu ache que isso causará alguma penalidade de desempenho.

@gsouf E acho que encontrei a última peça do quebra-cabeça (uma solução equivalente sem modificar o 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')

Oi @fnlctrl , obrigado pela saída e desculpe a demora.

De fato, parece que os componentes herdam componentes do construtor, não do pai. Atualmente procurando se posso aplicar um patch para o meu caso de uso.

No seu caso ele permanece anexado a um construtor, não a uma instância, procuro que faça parte apenas da instância

@fnlctrl devido à maneira como o javascript funciona e graças ao seu exemplo, eu poderia contornar isso "estendendo dinamicamente" o vue para cada instância que eu crio, disponibilizando tudo apenas para este aplicativo.:

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

Depois de verificar como o núcleo foi construído, ele não parece ter sido construído para permitir a fácil integração de componentes disponíveis por instância e esta solução alternativa é estável o suficiente para mim.

Obrigado pela ajuda!

Aliás, acho que o exemplo que você me mostrou poderia ser profundamente explicado no documento. não achei nenhuma menção sobre isso

@gsouf De nada. Acho que esse problema é suficiente para quem deseja implementar um recurso semelhante :smile:

Aqui eu tenho um caso de uso 'semi-global':

Eu tenho um componente de layout relativamente universal, mas o conteúdo é configurável pelos componentes que usam o componente de layout, por exemplo. componente A usa Layout e deseja configurar seu conteúdo com o componente B, algum outro componente pode usar Layout e configurar seu conteúdo com o componente C, etc.

Este padrão deve ser suportado?

Ou existe alguma solução para substituir este design?

O padrão é amplamente utilizado no iOS para melhorar a reutilização de código e este é um design flexível.

@hpsoar O que você provavelmente precisa é de slots

Meu Design é o seguinte, basicamente isso me permitirá fazer duas coisas com a célula:

  1. configuração simples da célula com um estilo css, que será suficiente para muitos casos;
  2. insira um componente na célula, que será usado para casos especiais.
<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>

Esta página foi útil?
0 / 5 - 0 avaliações