Day11-动态元件

这章节是延伸v-if和v-show管理元件,如何用更简便的方式做tab页签。

v-bind:is

做一个tab按钮切会下面显示的内容,直觉的方式是直接用v-if去写三个元件

<button v-for="tab in tabs" 
				:key="tab" 
				@click="currentTab = tab" 
				:class="{'active': currentTab === tab}">
	{{tab}}
</button>
<tab-a v-if="currentTab === 'A'"></tab-a>
<tab-b v-if="currentTab === 'B'"></tab-b>
<tab-c v-if="currentTab === 'C'"></tab-c>
const app = Vue.createApp({
    data() {
        return {
            currentTab: 'A',
            tabs: ['A', 'B', 'C']
        }
    }
});
app.component('tab-a', {
    template: `
    <h1>aaaaaaaaaaaaaaaaaa</h1>
    `
})
app.component('tab-b', {
    template: `
    <h1>bbbbbbbbbbbbbbbbbb</h1>
    `
})
app.component('tab-c', {
    template: `
    <h1>ccccccccccccccccc</h1>
    `
})

用更快的方式就是使用v-bind:is,新增一个computed,当点击按钮时会触发currentTab = tab,此时新的tab就会传到:is="currentTabComponent"身上,即显示出与用v-if一样的结果。

<button v-for="tab in tabs" 
				:key="tab" 
				@click="currentTab = tab" 
				:class="{'active': currentTab === tab}">
	{{tab}}
</button>
<component :is="currentTabComponent"></component>
const app = Vue.createApp({
    data() {
        return {
            currentTab: 'A',
            tabs: ['A', 'B', 'C']
        }
    },
    computed: {
        currentTabComponent() {
            return `tab-${this.currentTab.toLowerCase()}`;
        }
    }
});
app.component('tab-a', {
    template: `<h1>aaaaaaaaaaaaaaaaaa</h1>`
})

app.component('tab-b', {
    template: `<h1>bbbbbbbbbbbbbbbbbb</h1>`
})
app.component('tab-c', {
    template: `<h1>ccccccccccccccccc</h1>`
})

保留元件状态

改写刚刚的tab页签,内容物改成v-model绑定的input可以改写资料。

改写资料後按下其它标签会发先先前改写的资料会被还原成初始值。

app.component('tab-a', {
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'A component' })
})

app.component('tab-b', {
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'B component' })
})
app.component('tab-c', {
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'C component' })
})

若想让资料在切换时也能保持改写後的样子,就可以在外层包上keep-alive

<keep-alive>
  <component :is="currentTabComponent"></component>
</keep-alive>

补充: keep-alive同一时间只会有一个子元件被渲染

搭配的属性

  1. include / exclude 只保留/排除部分

使用时必须搭配name属性

<!-- 写法一:逗点格开 -->
<keep-alive include="A-TAB,B-TAB">
    <component :is="currentTabComponent"></component>
</keep-alive>
<!-- 写法二:Regular expression -->
<keep-alive :include="/(A|B)-TAB/">
    <component :is="currentTabComponent"></component>
</keep-alive>
<!-- 写法三:阵列 -->
<keep-alive :include="['A-TAB','B-TAB']">
    <component :is="currentTabComponent"></component>
</keep-alive>
app.component('tab-a', {
    name: 'A-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'A component' })
})

app.component('tab-b', {
    name: 'B-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'B component' })
})
app.component('tab-c', {
    name: 'C-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'C component' })
})
  1. max 限制元件数量

只保留最後引入的两个状态

<keep-alive :max="2">
    <component :is="currentTabComponent"></component>
</keep-alive>

特殊生命周期

生命周期中activateddeactivated两个hooks是给keep-alive使用的。

直接比对有和无keep-alive的差异在生命周期上有什麽不同。

做了同样的动作: 点击A标签→B标签→C标签

  • 有keep-alive

    切换时的顺序为「建立新元件created」→「暂停目前元件 deactivated」→「挂载新的元件 mounted」→「启用新的元件 activated」

    Untitled

  • 无keep-alive

    切换时的顺序为「建立新元件created」→「销毁目前元件 unmounted」→「挂载新的元件 mounted」

    Untitled

const app = Vue.createApp({
    data() {
        return {
            currentTab: 'A',
            tabs: ['A', 'B', 'C'],
            msgs: []
        }
    },
    computed: {
        currentTabComponent() {
            return `tab-${this.currentTab.toLowerCase()}`;
        }
    },
    methods: {
        notify(val) {
            this.msgs.push(val)
        }
    },
});
app.component('tab-a', {
    name: 'A-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'A component' }),
    created() {
        this.$emit('update', `${this.$options.name} Created`)
    },
    mounted() {
        this.$emit('update', `${this.$options.name} Mounted`)
    },
    unmounted() {
        this.$emit('update', `${this.$options.name} Unmounted`)
    },
    activated() {
        this.$emit('update', `${this.$options.name} Activated`)
    },
    deactivated() {
        this.$emit('update', `${this.$options.name} Deactivated`)
    }
})

app.component('tab-b', {
    name: 'B-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'B component' }),
    created() {
        this.$emit('update', `${this.$options.name} Created`)
    },
    mounted() {
        this.$emit('update', `${this.$options.name} Mounted`)
    },
    unmounted() {
        this.$emit('update', `${this.$options.name} Unmounted`)
    },
    activated() {
        this.$emit('update', `${this.$options.name} Activated`)
    },
    deactivated() {
        this.$emit('update', `${this.$options.name} Deactivated`)
    }
})

app.component('tab-c', {
    name: 'C-TAB',
    template: `<input type="text" v-model="title">`,
    data: () => ({ title: 'C component' }),
    created() {
        this.$emit('update', `${this.$options.name} Created`)
    },
    mounted() {
        this.$emit('update', `${this.$options.name} Mounted`)
    },
    unmounted() {
        this.$emit('update', `${this.$options.name} Unmounted`)
    },
    activated() {
        this.$emit('update', `${this.$options.name} Activated`)
    },
    deactivated() {
        this.$emit('update', `${this.$options.name} Deactivated`)
    }
})

<<:  Spring Framework X Kotlin Day 21 WebSocket

>>:  Day11 为什麽电脑能自动完成指令 - Lua 的多值回传

CSS微动画 - 弹出来的选单 Part.1

Q: 这个看起来像猫爪的东西是什麽? A: 喵? 本篇开始将实作选单的微动画,比较特别的要来说说t...

【Day06】提升(Hoisting)

我们在进到主题前先来看一段程序码,随後在开发人员工具中观察执行过程 function doSomet...

Day 03 - 行前说明 — 在 MVC & MVVM 的 UI 元件

相信网路上其实已经有不少文章在谈架构了,我的资历也尚浅,今天虽然会介绍架构,但是主要会侧重的点会是...

Day6 用python写UI-聊聊标签Label方法(一)

今天要来聊标签Label方法,这个部分会分成两个主题来讲,今天会先讲widget的共通属性,明天会讲...

Swift纯Code之旅 Day17. 「复习 - 新增页面、TableView、TableViewCell」

前言 目前标签页面的画面及功能已经完成,接下来继续新增「重复」页面,算是再熟悉一下TableView...