Vue学习篇-插槽、动态/异步组件、组件v-model

167 阅读1分钟

一、插槽

插槽内容

需在子组件内定义slot,否则父组件内子组件标签之间的内容将会被忽略掉

渲染作用域

默认情况下插槽内的内容只可访问父组件实例的数据

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的

备用内容

在子组件的<slot>我是备用内容</slot>标签内定义内容,未传入插槽内容时,将会作为备用内容显示

具名插槽

  • 未定义插槽名称的插槽将会默认为<slot name="default"></slot>,可给name设置名称
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
  • 在向具名插槽提供内容时,通过给template元素上添加v-slot来指明传递给哪一个插槽
<base-layout>
  <template v-slot:header>
    <h1>头部</h1>
  </template>
​
  <template v-slot:default>
    <p>默认内容</p>
  </template>
  
  <!-- 使用#进行缩写 -->
  <template #footer>
    <p>底部</p>
  </template>
</base-layout>

作用域插槽

  • 给子组件的slot上添加属性,可以在父组件的插槽内容中访问到该属性
<!-- 子组件 -->
<ul>
  <li v-for="( item, index ) in items">
    <slot :item="item" :index="index" :another-attribute="anotherAttribute"></slot>
  </li>
</ul><!-- 父组件 -->
<todo-list>
  <template v-slot:default="slotProps">
    <i class="fas fa-check">{{ slotProps.index }}</i>
    <span class="green">{{ slotProps.item }}</span>
  </template>
</todo-list>
  • 对于属性,可使用ES5解构(解构、起别名、默认值)
<!-- 父组件 -->
<todo-list>
  <template v-slot:default="{ item: todo, index, no = '默认值' }">
    <i class="fas fa-check">{{ index }}</i>
    <span class="green">{{ todo }}</span>
  </template>
</todo-list>

动态插槽

可使用变量来给插槽命名

<!-- 父组件 -->
<todo-list>
  <template v-slot:[变量]>
    ……
  </template>
</todo-list>

二、动态组件/异步组件

动态组件

<!-- component是vue自带组件 is是当前组件名称 属性正常传/接收 -->
<component :is="currentTabComponent" class="tab"></component>

懒加载(代码分离)

需要的时候再加载,称之为懒加载,也可实现代码分离,减少打包后的单个文件体积,webpack概念,vue-cli基于webpack,所以可直接使用

// 返回Promise对象
import(/* webpackChunkName: 'string' */ './lazy.js').then(result => {
    console.log(result);
});

异步组件

  • 基本用法
<async-com /><script setup>
    import { defineAsyncComponent } from 'vue';
    const asyncCom = defineAsyncComponent(() =>
      import(/* webpackChunkName: 'asyncCom' */'./asyncCom.vue')
    )
</script>
  • 高阶用法
<async-com /><script setup>
    import { defineAsyncComponent } from 'vue';
    const asyncCom = defineAsyncComponent({
        // 工厂函数
        loader: () => import('./asyncCom.vue'),
        // 加载异步组件时要使用的组件
        loadingComponent: LoadingComponent,
        // 加载失败时要使用的组件
        errorComponent: ErrorComponent,
        // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
        delay: 200,
        // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
        // 默认值:Infinity(即永不超时,单位 ms)
        timeout: 3000,
        // 定义组件是否可挂起 | 默认值:true
        suspensible: false,
        /**
           *
           * @param {*} error 错误信息对象
           * @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
           * @param {*} fail  一个函数,指示加载程序结束退出
           * @param {*} attempts 允许的最大重试次数
           */
          onError(error, retry, fail, attempts) {
                if (error.message.match(/fetch/) && attempts <= 3) {
                      // 请求发生错误时重试,最多可尝试 3 次
                      retry()
                } else {
                      // 注意,retry/fail 就像 promise 的 resolve/reject 一样:
                      // 必须调用其中一个才能继续错误处理。
                      fail()
                }
          } 
    })
</script>

三、组件v-model

基本写法

  • 父组件
<custom-input v-model="value"></custom-input><!-- 等价于 -->
<custom-input :model-value="modelValue" @update:model-value="value"></custom-input>
  • 子组件
// 方法一
<temlplate>
    <input :value="props.modelValue" @input="input" />
</temlplate><script setup>
    const props = defineProps(['modelValue']);
    const emits = defineEmits(['update:modelValue']);
    
    const input = e => {
        emits('update:modelValue', e.detail.value)
    }
</script>

// 方法二
<temlplate>
    <input v-modal="value" />
</temlplate>

<script setup>
    import { computed } from 'vue';
    const props = defineProps(['modelValue']);
    const emits = defineEmits(['update:modelValue']);
    
    const value = computed({
        get: () => props.modelValue,
        set: val => {
            emits('update:modelValue', val)
        }
    })
</script>

定义名称(多个v-model绑定)

  • 父组件
<custom-input v-model:noice="noice" v-model:lee="lee"></custom-input>
  • 子组件
<temlplate>
    <input :value="props.noice" @input="noiceInput" />
    <input :value="props.lee" @input="leeInput" />
</temlplate>
​
<script setup>
    const props = defineProps(['noice', 'lee']);
    const emits = defineEmits(['update:noice', 'update:lee']);
    
    const noiceInput = e => {
        emits('update:noice', e.detail.value);
    };
    const leeInput = e => {
        emits('update:lee', e.detail.value);
    }
</script>

修饰符

  • 父组件
<custom-input v-model:noice.lower="noice"></custom-input>
  • 子组件
<temlplate>
    <input :value="props.noice" @input="noiceInput" />
</temlplate>
​
<script setup>
    const props = defineProps(['noice', 'noiceModifiers']);
    const emits = defineEmits(['update:noice', 'update:lee']);
    
    const noiceInput = e => {
        let value = e.detail.value;
        if (props.noiceModifiers.lower) {
            value = value.toLowerCase();
        }
        emits('update:noice', value);
    };
</script>

参考

Vue3中文网