Recursos do Vue para lembrar

Nós, da equipe de Ptah , decidimos ir um pouco além do SPA habitual e tentamos usar o Vue como designer de landing page. E agora queremos compartilhar parte da nossa experiência.

Este artigo é principalmente para aqueles que acabaram de começar a trabalhar com o Vue e desejam conhecer melhor seus recursos e capacidades. Aqui, quero falar sobre alguns dos recursos da estrutura, que muitas vezes permanecem imerecidamente esquecidos pelos desenvolvedores iniciantes.

Funções de renderização


Modelos de componentes são uma das coisas pelas quais os desenvolvedores adoram o Vue. Eles são simples e lógicos, graças a eles, o quadro tem um limite de entrada baixo. A sintaxe do modelo é suficiente em 90% dos casos para escrever código lógico e bonito. Mas o que fazer se você estiver nos 10% restantes e não conseguir escrever um componente compacto? A função de renderização o ajudará.

Vamos ver o que está usando o exemplo da documentação:

Vue.component('anchored-heading', {
 render: function (createElement) {
   return createElement(
     'h' + this.level,   //  
     this.$slots.default //   
   )
 },
 props: {
   level: {
     type: Number,
     required: true
   }
 }
})

O componente de cabeçalho ancorado aceita a propriedade level e desenha a tag title. Assim gravando

<anchored-heading :level="1">, !</anchored-heading>

Será convertido para

<h1>, !</h1>

Se esse componente fosse descrito usando um modelo padrão, ele conteria até 6 v-if condições que descrevem diferentes níveis de cabeçalhos:

<h1 v-if="level === 1">
 <slot></slot>
</h1>
<h2 v-if="level === 2">
 <slot></slot>
</h2>
<h3 v-if="level === 3">
 <slot></slot>
</h3>
<h4 v-if="level === 4">
 <slot></slot>
</h4>
<h5 v-if="level === 5">
 <slot></slot>
</h5>
<h6 v-if="level === 6">
 <slot></slot>
</h6>

Como funciona?


O método render usa dois argumentos. O primeiro argumento para createElement é uma função que descreve qual elemento do Vue deve criar. Na comunidade, é habitual abreviar createElement para uma letra - h . O segundo argumento é contexto , para acessar dados de contexto.

createElement usa três argumentos:

  1. O item a ser criado. Isso pode ser não apenas uma tag HTML, mas também um nome de componente. Este argumento é obrigatório;
  2. Um objeto com dados. Pode conter uma lista de classes, estilos, parâmetros de entrada para o componente, métodos para manipulação de eventos, etc. Para mais detalhes, consulte a documentação. Argumento opcional;
  3. Nós virtuais filhos. Pode ser uma sequência ou uma matriz. No exemplo acima, é este. $ Slots.default .

As funções de renderização podem ajudar nas situações mais inesperadas. Por exemplo, em Ptah, geralmente precisamos usar a tag style na página para que alguns elementos do designer funcionem corretamente. No entanto, o Vue proíbe o uso dessa tag dentro do componente do modelo . Essa limitação é facilmente contornada graças a um pequeno invólucro:

Vue.component('v-style', {
 render: function (h) {
   return h('style', this.$slots.default)
 }
})

Agora, dentro dos modelos, em vez da tag style , você pode usar o estilo v .

Portanto, assim que começar a parecer que os recursos padrão dos modelos do Vue não são suficientes - pense nas funções de renderização. Eles parecem complicados apenas à primeira vista, mas você pode usar todos os recursos que o JS fornece neles.

Mixins


Você tem vários componentes semelhantes com código duplicado? Mixins ou impurezas ajudarão a cumprir o princípio DRY - a funcionalidade dos mixins pode ser usada em vários componentes ao mesmo tempo.

Vamos dar um exemplo. Digamos que temos 2 componentes com lógica semelhante:

export default  {
  name: 'TextElement',

  data () {
    return {
      elementName: 'Text',
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

export default  {
  name: 'ButtonElement',

  data () {
    return {
      elementName: 'Button',
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

Os componentes são diferentes, mas têm a mesma lógica. Para fazer isso, você precisará criar um arquivo js regular. Seria lógico colocá-lo no diretório mixins ao lado dos componentes.

// mixin.js
export default  {
  data () {
    return {
      showEditor: false,
      editor: null
    }
  },
  
  methods: {
    initEditor () {
      this.showEditor = true
      this.editor = new Editor(this.elementName)
    }
  }
}

// TextElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'TextElement',

  mixins: [mixin]  //  

  data () {
    return {
      elementName: 'Text',
    }
  },
}

// ButtonElement.vue
import mixin from './mixins/mixin'

export default  {
  name: 'ButtonElement',

  mixins: [mixin]

  data () {
    return {
      elementName: 'Button'
    }
  }
}

Como você pode ver no exemplo, quase toda a lógica migrou para o mixin. Ao usar impurezas dentro dos componentes, todas as opções são mescladas. E no componente, você pode chamar livremente o método initEditor () e, inversamente, na impureza, o elementName do componente é usado aqui . Nesse caso, os objetos de dados serão mesclados recursivamente e as propriedades do componente terão precedência.

Portanto, os benefícios das impurezas são óbvios - isso é reutilização de código. Mas há um sinal de menos. Este exemplo é sintético, apenas algumas linhas. Componentes reais, como os usados ​​no Ptah, podem ser escritos em algumas centenas de linhas de código. Nem sempre será claro para uma pessoa que não escreveu esse código como ele funciona, especialmente se ele ignora a adição de mixins ao componente. Infelizmente, livrar-se disso menos não funcionará. Posso recomendar duas coisas: descreva a operação do componente no JSDoc e use nomes especiais para propriedades da impureza (por exemplo, você pode adicionar um prefixo, que você concordará com a equipe antecipadamente).

Fornecer / Injetar


Esse par de opções é sempre usado em conjunto e permite transferir dados do componente pai para toda a hierarquia de seus descendentes. Essas opções são usadas principalmente para escrever plug-ins, a documentação oficial não recomenda o uso em aplicativos. Nos aplicativos, a comunicação entre os componentes se baseia muito bem no Vuex. No entanto, essa funcionalidade ainda merece atenção.

Como funciona?


Primeiro, precisamos definir os dados no componente pai, que passaremos para seus descendentes.

// Parent.vue        
export default {
  provide: {
   device: 'is-desktop'
  }
}

Agora os dados transferidos precisam ser incorporados no componente filho.

// Child.vue    
export default {
  inject: ['device'],

  created () {
   console.log(this.device) // => "is-desktop"
  }
}

Como você pode ver no exemplo, tudo é bem simples. Mas um menos significativo deve ser observado - os dados do pacote de fornecimento / injeção não são reativos por padrão! No entanto, essa desvantagem é facilmente contornada usando Object.defineProperty :

provide () {
 let device = {}
 Object.defineProperty(device, 'type', { enumerable: true, get: () => this.device })
 return { device }
},

data () {
 return {
   device: 'is-desktop'
 }
}

Agora, alterar este dispositivo no pai mudará nos descendentes.

Meta do componente


Há situações em que não se sabe com antecedência qual componente será usado no código. Considere um exemplo do nosso editor. A tarefa é a seguinte: na seção condicional do FirstScreen, mostre os elementos Texto, Logotipo, Botão e adicione SocialIcons a esses elementos .

Portanto, é óbvio que teremos um componente de seção que servirá como um contêiner para os elementos e 4 componentes para os próprios elementos. A estrutura será aproximadamente da seguinte maneira:

/ sections
 -- FirstScreen.vue
/ elements
 -- Text.vue
 -- Logo.vue
 -- Button.vue
 -- SocialIcons.vue

Adicionar todos os componentes dos elementos ao modelo FirstScreen de uma vez e depois alterná- los usando condições seria uma decisão extremamente imprudente. Existe uma ferramenta simples e maravilhosa para essas tarefas:

<component :is="%componentName%"/>

O elemento component com o atributo : is , que simplesmente grava o nome do componente. E graças a ele, nossa tarefa é simplesmente resolvida:

<script>
export default  {
  name: 'FirstScreen',

  data () {
    return {
      elements: [
        'Text',
        'Logo',
        'Button',
      ],
    }
  }
}
</script>

<template>
  <div class="first-screen">
    <component v-for="element in elements" :is="element"/>
  </div>
</template>

Na matriz de elementos , escrevemos os nomes dos componentes e, em seguida, simplesmente produzimos esses componentes em um loop dentro do modelo FirstScreen . Agora, para adicionar um elemento com ícones de redes sociais à nossa seção, precisamos apenas executar this.elements.push ('SocialIcons') .

All Articles