Uso básico da configuração do Vue3 e do açúcar de sintaxe de configuração

Quando a configuração é executada

setup é usado para escrever API combinada, do ponto de vista da função de gancho do ciclo de vida, é equivalente a substituir beforeCreate e será executado antes de ser criado.

setup(props) {
  console.log("setup", props);
},
beforeCreate() {
  console.log("beforeCreate");
},
created() {
  console.log("created");
},

Após a execução, o resultado da impressão de configuração está sempre na frente.

Como os dados e métodos de configuração são usados

As propriedades e métodos dentro do setup devem ser expostos por return para montar as propriedades na instância, caso contrário não há como utilizá-los:

<template>
  <div class="hello">
    <h1>{
   
   { msg }}</h1>
  </div>
</template>
setup(props) {
  let msg = "hello";
  return {
    msg,
  };
},

Existe isso dentro da configuração?

Imprima isso na configuração por conta própria e o resultado retornado é indefinido. Porque o setup será executado uma vez antes de beforeCreate, então isso é indefinido, isso não existe dentro do setup, e as coisas relacionadas a isso não podem ser montadas.

setup(props) {
  console.log("setup", props);
  console.log("setup this", this);
},
beforeCreate() {
  console.log("beforeCreate");
},
created() {
  console.log("created");
},

Como usar a função de gancho na configuração

Vue3 é um método de escrita no estilo de opção que é compatível com vue2, então a função hook pode existir lado a lado com a configuração, que é equivalente à API de opções; mas se houver um conflito entre as configurações de vue2 e vue3, o configuração de vue3 tem precedência.

export default{ 
    setup(){  
        console.log('setup'); 
    }, 
    mounted(){  
        console.log('mounted'); 
    }
}

A nova função setup() do vue3 é usada para escrever API combinada, então não é recomendado escrever código como este. Portanto, você precisa usar a família de funções onXXX para registrar a função de gancho. Após o registro ser bem-sucedido, uma função de retorno de chamada é passada ao chamar.  

import { onMounted } from "vue";
export default{ 
    setup(){  
        const a = 0  
        return{   a  }  
        onMounted(()=>{   
            console.log("执行"); 
        }) 
    }
}

Essas funções de gancho de ciclo de vida registradas só podem ser usadas de forma síncrona durante a configuração, porque dependem do estado interno global para localizar a instância do componente atual e um erro será lançado quando a função não for chamada no componente atual.

As outras funções de gancho são as mesmas, basta importá-las conforme necessário.

A relação entre configuração e função de gancho

Quando a configuração é paralela às funções de gancho, a configuração não pode chamar funções relacionadas ao ciclo de vida, mas o ciclo de vida pode chamar propriedades e métodos relacionados à configuração.

<template> 
    <button @click="log">点我</button>
</template><script>

export default{ 
    setup(){  
        const a = 0  return{   a  } 
    }, 
    methods:{  
        log(){   
            console.log( this.$options.setup() );//返回一个对象  
        } 
    }
}
</script>

this.$options.setup() retorna um objeto grande, que contém todas as propriedades e métodos na configuração.

parâmetro de configuração

Ao usar o setup, ele receberá dois parâmetros: **props e context. **

adereços

O primeiro parâmetro é props, o que significa que o componente pai passa o valor para o componente filho, e a propriedade recebida é declarada dentro do componente. Quando recebidos no componente filho, os dados recebidos são empacotados em um objeto proxy, que pode realizar capacidade de resposta Ao passar Atualiza automaticamente quando novos adereços são importados.

export default{ 
    props: {  
        msg: String,  
        ans: String, 
    }, 
    setup(props,context){  
        console.log(props);//Proxy {msg: "着急找对象", ans: "你有对象吗?"} 
    },
}

Como props é responsivo, a desconstrução do ES6 não pode ser usada, o que eliminará a capacidade de resposta dos props. Nesse caso, a desconstrução toRefs precisa ser emprestada.

import { toRefs } from "vue"; 
export default{  
    props: {   
        msg: String,   
        ans: String,  
    },  
    setup(props,context){   
        console.log(props);   
        const { msg,ans } = toRefs(props)   
        console.log(msg.value); //着急找对象   console.log(ans.value); //你有对象吗?  
    }, 
}

Ao usar componentes, muitas vezes encontramos parâmetros opcionais. Alguns lugares precisam passar um determinado valor, e outras vezes não. Como lidar com isso?

Se ans for um parâmetro opcional, ans não pode ser passado em props. Nesse caso, toRefs não criará uma referência para ans e, em vez disso, toRef precisa ser usado.

import { toRef } from "vue";
setup(props,context){ 
    let ans  = toRef(props ,'ans')// 不存在时,创建一个ans 
    console.log(ans.value);
}

contexto

contexto O ambiente de contexto, que inclui três partes: atributos, slots e eventos personalizados.

setup(props,context){ 
    const { attrs,slots,emit } = context // attrs 获取组件传递过来的属性值, // slots 组件内的插槽 // emit 自定义事件 子组件
}
  • attrs é um objeto não responsivo, que recebe principalmente o atributo no-props passado de fora do componente. Muitas vezes é usado para passar alguns atributos de estilo, mas os atributos que não são declarados na configuração de props são equivalentes a; durante a comunicação processo entre componentes pai e filho, o componente pai envia this.$attrsdados Passado, se o subcomponente não for recebido com props, ele aparecerá em attrs, mas não em vm. Se for recebido com props, aparecerá em vm, mas não em atrs.

  • slots é um objeto proxy, onde slots.default() obtém um array, o comprimento do array é determinado pelo slot do componente e o conteúdo do slot está dentro do array.

  • emit: Uma função que distribui eventos personalizados, equivalente a this.$emit.

Isso não existe na configuração, portanto, emit é usado para substituir o this.$emit anterior e é usado quando o filho é passado para o pai e o evento personalizado é acionado.

<template> 
    <div :style="attrs.style">  
        <slot></slot>    
        <slot name="hh"></slot>  
		<button @click="emit('getVal','传递值')">子向父传值</button>  
	</div> 
</template>

<script>
import { toRefs,toRef } from "vue";
export default{ 
    setup(props,context){  
        const { attrs,slots,emit } = context  // attrs 获取组件传递过来 style 属性     
        console.log('slots',slots.default());//插槽数组 
        console.log('插槽属性',slots.default()[1].props); //获取插槽的属性    
        return{  attrs,  emit   }  
    }, 
}
</script>

Resumo dos recursos de configuração

  • Esta função será executada antes de ser criada, conforme explicado acima.

  • Não há isso dentro da configuração e as coisas relacionadas a isso não podem ser montadas.

  • As propriedades e métodos dentro do setup devem ser expostos por meio de return, caso contrário não há como utilizá-los.

  • Os dados internos de configuração não são reativos.

  • A configuração não pode chamar funções relacionadas ao ciclo de vida, mas funções de ciclo de vida podem chamar funções na configuração.

Pontos a observar: (1) Tente não misturar as configurações de vue2 e vue3 (2) a configuração não pode ser uma função assíncrona, porque o valor de retorno não é mais o objeto de retorno, mas uma promessa, e o modelo não pode ver os atributos em o objeto de retorno. (Você também pode retornar uma instância de Promise posteriormente, mas requer a cooperação de Suspense e componentes assíncronos)

// 引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'

// 创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”)
const app = createApp(App)

// 挂载
app.mount('#app')

<configuração do script> açúcar sintático

<script setup>Variáveis, funções e conteúdo introduzido por importação que não precisam ser declarados em retorno podem ser <template/>usados ​​em

<script setup>
import { getToday } from './utils'
// 变量
const msg = 'hello'
// 函数
function log() {
    console.log(msg)
}
</script>

// 在 templete 中直接使用声明的变量、函数以及 import 引入的内容
<template>
    <div @click="log">{
   
   { msg }}</div>
	<p>{
   
   { getToday() }}</p>
</template>

O componente padrão <script> precisa escrever a função de configuração e retornar return

<script>
//import引入的内容
import { getToday } from './utils'  
export default{
 setup(){
    // 变量
    const msg = 'Hello!'
    // 函数
    function log() {
      console.log(msg)
    }
    //想在tempate里面使用需要在setup内return暴露出来
    return{
       msg,
       log,
       getToday 
    }
 }
}
</script>

<template>
  <div @click="log">{
   
   { msg }}</div>
   <p>{
   
   {getToday()}}</p>
</template>

O código no açúcar sintático <script setup> será compilado no conteúdo da função setup() do componente e quaisquer ligações no nível superior da instrução `<script setup>` (incluindo variáveis, funções e o conteúdo introduzido por `import`) pode ser usado diretamente no template, sem expor as variáveis ​​declaradas, funções e conteúdo de importação através de return, pode ser usado em <templet>, e não há necessidade de escrever export default{}, quando usando `<configuração do script>` .

O código no açúcar sintático <script setup> será compilado no conteúdo da função setup() do componente. Isso significa que, ao contrário do <script> normal, que é executado apenas uma vez quando o componente é introduzido pela primeira vez, o código dentro do <script setup> será executado toda vez que a instância do componente for criada

<script>
  console.log('script');//多次实例组件,只触发一次
  export default {
      setup() {
          console.log('setupFn');//每次实例化组件都触发和script-setup标签一样
      }
  }
  </script>

A tag <script setup> eventualmente será compilada no setup()conteúdo da função e toda vez que o componente for instanciado, a função de configuração será instanciada uma vez. A função de configuração na tag de script também é a mesma. Toda vez que você instanciar um componente, você instancia a função de configuração uma vez, mas a configuração da tag de script precisa ser escrita no padrão de exportação{}, e a parte externa só é executada uma vez quando é introduzido pela primeira vez.

<script setup>Os componentes importados serão registrados automaticamente

Não há necessidade de registrar o componente através de `components:{}` após importar o componente, ele pode ser usado diretamente

<script setup>
import MyComponent from './MyComponent.vue'
//components:{MyComponent}  不需要注册直接使用
</script>

<template>
  <MyComponent />
</template>

Como os componentes são referenciados como variáveis ​​em vez de registrados como chaves de string, <script setup>ao usar componentes dinâmicos em , você deve usar :isa ligação dinâmica

comunicação componente

<script setup>deve usar definePropse defineEmitsAPI em vez de adereços e emite em

`defineProps` e `defineEmits` têm inferência de tipo completa e estão disponíveis diretamente em `<script setup>` (depois de navegar no Nuggets, descobri que a maioria das demos do artigo ainda introduz essas duas APIs por meio de importação, que é o documento oficial claramente escrito)

defineProps ao invés de props, recebe os dados passados ​​pelo componente pai (o componente pai passa parâmetros para o componente filho)

componente pai:

<template>
  <div>父组件</div>
  <Child :title="msg" />
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const msg = ref('父的值')  //自动返回,在template直接解套使用
</script>

Submontagem:

  • <template/>Você pode usar diretamente as props passadas pelo componente pai (as props podem ser omitidas).

  • <script-setup>Precisa obter as props passadas pelo componente pai por meio de props.xx

<template>
  <div>子组件</div>
  <div>父组件传递的值:{
   
   {title}}</div>
</template>

<script setup>
//import {defineProps} from 'vue'   不需要引入

//语法糖必须使用defineProps替代props
const  props = defineProps({
  title: {
    type: String
  }
});
//script-setup 需要通过props.xx获取父组件传递过来的props
console.log(props.title) //父的值
</script>

defineEmit substitui emit, o componente filho passa dados para o componente pai (o componente filho expõe dados para fora)

Código do subcomponente:

<template>
  <div>子组件</div>
  <button @click="toEmits">子组件向外暴露数据</button>
</template>

<script setup>
import {ref} from 'vue'
const name = ref('我是子组件')
//1、暴露内部数据
const  emits = defineEmits(['childFn']);

const  toEmits = () => {
  //2、触发父组件中暴露的childFn方法并携带数据
  emits('childFn',name)
}
</script>

Código do componente pai:

<template>
  <div>父组件</div>
  <Child  @childFn='childFn' />
  <p>接收子组件传递的数据{
   
   {childData}} </p>
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
    
const childData = ref(null)    
const childFn=(e)=>{
    consloe.log('子组件触发了父组件childFn,并传递了参数e')
    childData=e.value
}    
</script>

<script setup>É necessário expor ativamente as propriedades do componente filho ao componente pai: defineExpose

<script setup>Para componentes que usam , o componente pai não pode $parentobter dados de resposta, como o ref do componente filho por meio de ref ou , e precisa expô-lo ativamente por meio de defineExpose

Código do subcomponente:

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)
//主动暴露组件属性
defineExpose({
  a,
  b
})
</script>

Código do componente pai:

<template>
  <div>父组件</div>
  <Child  ref='childRef' />
  <button @click='getChildData'>通过ref获取子组件的属性 </button>
</template>

<script setup>
import {ref} from 'vue'
import Child from './child.vue'
const childRef= ref()  //注册响应数据  
const getChildData =()=>{
  //子组件接收暴露出来得值
  console.log(childRef.value.a) //1
  console.log(childRef.value.b) //2  响应式数据
}    
</script>

Açúcar sintático para outros recursos

`useSlots` e `useAttrs` (** raramente usado**, já que a maioria das pessoas está desenvolvendo no modo SFC, os slots podem ser renderizados através da tag `<slot/>` em `<template/>`)

Se você precisa usar `slots` e `attrs` em `script-setup`, você precisa usar `useSlots` e `useAttrs`

Precisa introduzir: `import { useSlots ,useAttrs } form 'vue'`

É mais conveniente acessar através de `$slots` e `$attrs` em `<template/>` (attrs é usado para obter os parâmetros/métodos non-props passados ​​para o componente filho no componente pai, e attrs é usado para obter non-props no componente pai Parâmetros/métodos passados ​​de props para subcomponentes, attrs são usados ​​para obter parâmetros/métodos non-props passados ​​para subcomponentes no componente pai, slots podem obter objetos virtuais dom passados ​​por slots no componente pai , e não deve ser útil no modo SFC Large, usado mais em JSX/TSX)

componente pai:

<template>
  <Child msg="非porps传值子组件用attrs接收" >
    <!-- 匿名插槽 -->
    <span >默认插槽</span>
    <!-- 具名插槽 -->
    <template #title>
      <h1>具名插槽</h1>
    </template>
    <!-- 作用域插槽 -->
    <template #footer="{ scope }">
      <footer>作用域插槽——姓名:{
   
   { scope.name }},年龄{
   
   { scope.age }}</footer>
    </template>
  </Child>
</template>

<script setup>
// 引入子组件
import Child from './child.vue'
</script>

Submontagem:

<template>
  <!-- 匿名插槽 -->
  <slot />
  <!-- 具名插槽 -->
  <slot name="title" />
  <!-- 作用域插槽 -->
  <slot name="footer" :scope="state" />
  <!-- $attrs 用来获取父组件中非props的传递到子组件的参数 -->
  <p>{
   
   { attrs.msg == $attrs.msg }}</p>
  <!--true  没想到有啥作用... -->
  <p>{
   
   { slots == $slots }}</p>
</template>

  
<script setup>
import { useSlots, useAttrs, reactive, toRef } from 'vue'
const state = reactive({
  name: '张三',
  age: '18'
})

const slots = useSlots()
console.log(slots.default()); //获取到默认插槽的虚拟dom对象
console.log(slots.title());   //获取到具名title插槽的虚拟dom对象
// console.log(slots.footer()); //报错  不知道为啥有插槽作用域的无法获取
//useAttrs() 用来获取父组件传递的过来的属性数据的(也就是非 props 的属性值)。
const attrs = useAttrs()
</script>

Roteamento de acesso na configuração

Acessar informações do componente da instância de roteamento: rota e roteador

`this` não pode ser acessado em `setup`, e `this.$router` ou `this.$route` não podem mais ser acessados ​​diretamente. (getCurrentInstance pode substituir isso, mas não é recomendado)

Recomendação: use as funções `useRoute` e `useRouter` ao invés de `this.$route` e `this.$router`

<script setup>
import { useRouter, useRoute } from 'vue-router'
    const route = useRoute()
    const router = useRouter()
    
    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
        },
      })
    }
<script/>

guarda de navegação

Os protetores de navegação para componentes de instância de rota ainda podem ser usados

import router from './router'
router.beforeEach((to,from,next)=>{

})

Você também pode usar o guarda de navegação da API combinadaonBeforeRouteLeave, onBeforeRouteUpdate

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

    // 与 beforeRouteLeave 相同,无法访问 `this`
    onBeforeRouteLeave((to, from) => {
      const answer = window.confirm(
        'Do you really want to leave? you have unsaved changes!'
      )
      // 取消导航并停留在同一页面上
      if (!answer) return false
    })

    const userData = ref()

    // 与 beforeRouteUpdate 相同,无法访问 `this`
    onBeforeRouteUpdate(async (to, from) => {
      //仅当 id 更改时才获取用户,例如仅 query 或 hash 值已更改
      if (to.params.id !== from.params.id) {
        userData.value = await fetchUser(to.params.id)
      }
    })
<script/>

As guardas de API compostas também podem ser usadas em qualquer componente <router-view>renderizado , elas não precisam ser usadas diretamente em componentes de roteamento como as guardas no componente fazem.

Use com script normal

<script setup> pode ser usado com <script> normal. O <script> comum pode ser usado nesses casos.

  • Não pode ser usado em <script setup>opções declaradas, como inheritAttrsopções personalizadas habilitadas por plugins

  • Declarar exportações nomeadas

  • Execute efeitos colaterais ou crie objetos que só precisam ser executados uma vez

<script>
    // 普通 <script>, 在模块范围下执行(只执行一次)
    runSideEffectOnce()
    
    // 声明额外的选项
    export default {
      inheritAttrs: false,
      customOptions: {}
    }
</script>

<script setup>
    // 在 setup() 作用域中执行 (对每个实例皆如此)
</script>

Resumo: O açúcar sintático da configuração é um complemento do Vue3, tornando o Vue3 mais completo.

<script setup> é um açúcar sintático em tempo de compilação para usar a API de composição em componentes de arquivo único. Tem muitas vantagens sobre a sintaxe <script> normal

  • Menos conteúdo clichê, código mais conciso
  • Capacidade de declarar props e lançar eventos usando Typescript puro
  • Melhor desempenho em tempo de execução (seu modelo será compilado em uma função de renderização no mesmo escopo que ele, sem nenhum proxy intermediário)
  • Melhor desempenho de inferência de tipo IDE (menos trabalho para o servidor de linguagem extrair tipos do código)

Acho que você gosta

Origin blog.csdn.net/qq_43641110/article/details/129981821
Recomendado
Clasificación