IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue3学习随便记11 -> 正文阅读

[JavaScript知识库]vue3学习随便记11

深入组件

Provide/Inject

通常,我们需要把数据从父组件向子组件传递时,使用 prop。但对于深度嵌套的组件系统,有时候,深层子组件需要父组件的部分内容,此时,仍然使用 prop机制会非常麻烦。例如,爷爷a 要把数据传递给孙子 c1,使用 prop机制就必须 b2 定义prop,从a获得数据,c1再定义prop,从b2把那个数据再传递一下。?

对于如下组件层次结构

Root
└─ TodoList
   ├─ TodoItem
   └─ TodoListFooter
      ├─ ClearTodosButton
      └─ TodoListStatistics

如果要将 todo-list 中 item 的数目直接传递给 todo-list-statistics,按prop机制传递为:todo-list?-> todo-list-footer -> todo-list-statistics 。我们使用 Provide/Inject 机制,可以直接让 todo-list 提供依赖项(它不清楚谁依赖这个数据,只是导出),然后 todo-list-statistics 注入依赖项(它不清楚依赖来自谁,只是知道可以导入),注入的依赖项就成为todo-list-statistics的数据属性(注入属性)。我们从前一篇的例子上修改

    <div id="app">
        <todo-list :title="title">
            <template #default="{ index: i, item: todo }">
                <span>++ {{ i }} ++ </span>
                <span>{{ todo }}</span>
            </template>
            <template #other="{ date: date }">
                <hr>
                <p>{{ date }}</p>
            </template>
        </todo-list>
    </div>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    title: '张三的下班生活'
                }
            }
        })
        app.component('todo-list', {
            props: ['title'],
            data() {
                return {
                    items: ['下班', '洗手', '吃饭', '散步', '睡觉'],
                    date: '2021-11-11'
                }
            },
            provide: {
                user: '李四'
            },
            template: `
                <h2>{{ title }}</h2>
                <ul>
                    <li v-for="(item, index) in items">
                        <slot :item="item" :index="index"></slot>
                    </li>
                </ul>
                <slot :date="date" name="other"></slot>
                <todo-list-footer></todo-list-footer>
            `
        })
        app.component('todo-list-footer', {
            template: `
                <todo-list-statistics></todo-list-statistics>
            `
        })
        app.component('todo-list-statistics', {
            inject: ['user'],
            created() {
                console.log(`Injected property: ${this.user}`)
            },
            template: `记录人:{{ user }}`
        })
        app.mount('#app')

?在上述代码中,我们让 todo-list Provide 了一个静态字符串数据user,如果我们想 Provider 组件实例的 property,例如 items 的条目数,下述代码不能达到目的

            provide: {
                user: '李四',
                itemsCount: this.items.length // Cannot read properties of undefined (reading 'length')
            },

我们必须把 provide 从静态对象转换成返回对象的函数:

            provide() {
                return {
                    user: '李四',
                    itemsCount: this.items.length
                }
            },

使用则是类似的(当做组件的数据属性)

        app.component('todo-list-statistics', {
            inject: ['user', 'itemsCount'],
            created() {
                console.log(`Injected property: ${this.user}、${this.itemsCount}`)
            },
            template: `共 {{ itemsCount }} 条,记录人:{{ user }}`
        })

动态组件与异步组件

在动态组件上使用 keep-alive

在前面的多标签界面实例中,我们了解了动态组件,即用 is attribute 来切换不同的组件:

<component :is="currentTabComponent"></component>

默认来回在这些 tab 页切换时,会反复渲染,对性能有一定影响,因此,我们可能想保持这些组件的状态。另一想保持组件状态的原因是,默认我们在 Posts 页选择了某篇帖子阅读,中途切换到 Archive 页,然后切换回 Posts 页,就回不到刚才阅读的那篇帖子,因为每次切换新标签页,Vue都创建新的?currentTabComponent 实例。要实现上述意图,我们需要一种缓存机制:用一个 <keep-alive> 元素将动态组件包裹起来

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component :is="currentTabComponent"></component>
</keep-alive>

下面给出简单的实例(可以试验没有 keep-alive 和 有 keep-alive 时,输入 input 的内容是否保持):

    <div id="app">
        <button v-for="tab in tabs" :key="tab.name"
            :class="['tab-button', {active: currentTab === tab.name}]"
            @click="currentTab = tab.name">
            {{ tab.text }}
        </button>
        <keep-alive>
            <component :is="currentTabComponent" class="tab"></component>
        </keep-alive>
    </div>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    currentTab: 'Home',
                    tabs: [
                        {name:'Home', text:'首页'},
                        {name:'Posts', text:'帖子'},
                        {name:'Archive', text:'归档'}
                    ]
                }
            },
            computed: {
                currentTabComponent() {
                    return 'tab-' + this.currentTab.toLowerCase()
                }
            }
        })
        app.component('tab-home', {
            template: `<div class="demo-post">首页内容</div>`
        })
        app.component('tab-posts', {
            template: `<div class="demo-post">帖子……<input type="text" /></div>`
        })
        app.component('tab-archive', {
            template: `<div class="demo-post">(归档)</div>`
        })
        const vm = app.mount('#app')
    </script>

异步组件

?在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了实现这个效果,Vue提供了 defineAsyncComponent 方法实现异步组件。

    <div id="app">
        <async-example></async-example>
    </div>
    <script>
        const { createApp, defineAsyncComponent } = Vue
        const app = createApp({})
        const AsyncComp = defineAsyncComponent(() => new Promise(
            (resolve, reject) => {
                setTimeout(() => {
                    let data = { template: '<div>这是异步的!</div>' }
                    resolve(data)
                }, 2000)
            }
        ))
        app.component('async-example', AsyncComp)
        app.mount('#app')
    </script>

上面的例子中,我们用延时模拟从服务器加载。defineAsyncComponent 函数的参数是一个返回 Promise 的工厂函数。从服务器检索组件定义后(例子中 data),应调用 Promise 的 resolve 回调 (也可以在失败时调用 reject(reason))。我们从调试插件可以了解到,对于异步组件,有一个 AsyncComponentWrapper 节点,初始它是空的,等到从服务器获得数据后,内部节点(匿名组件)Anonymous Component 就产生了。

使用编译构建工具和ES2015+语法,可以实现动态导入

import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/AsyncComponent.vue')
)

app.component('async-component', AsyncComp)

局部注册的组件也可以动态导入

import { createApp, defineAsyncComponent } from 'vue'

createApp({
  // ...
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./components/AsyncComponent.vue')
    )
  }
})

模板引用

?我们知道,可以通过组件 prop 和 组件事件 实现父级和子组件的通信(父级向子组件传递数据,传递事件回调处理),但有时我们仍然想直接访问子组件。使用 ref attribute 可以为子组件或HTML 元素指定引用ID(带有 ref 属性的模板将变成可引用对象,有点直接访问DOM节点的意思)。下面的例子我们使用模板引用特性让初始光标焦点在第二个输入框组件上

    <div id="app">
        <base-input ref="usernameInput"></base-input>
        <base-input ref="nicknameInput"></base-input>
    </div>
    <script>
        const { createApp } = Vue
        const app = createApp({})
        app.component('base-input', {
            template: `<input ref="input" />`,
            methods: {
                focusInput() {
                    this.$refs.input.focus()
                }
            }
        })
        const vm = app.mount('#app')
        vm.$refs.nicknameInput.focusInput()
    </script>

vm实例property $refs 是一个对象,它包括了注册过 ref attribute 的所有DOM元素和组件实例,所有 ref attribute 的值对应该对象的键。$refs 只会在组件渲染完成后生效,并且它本质上就是在直接访问DOM,这和Vue的虚拟DOM精神是违背的,所以,这种机制只是一种弥补机制,应该避免在模板或计算属性中访问 $refs (通常在 mounted() 钩子等使用)

处理边界情况

控制更新

我们知道,Vue是响应式系统,一般它自己知道何时应该更新。但是,某些极端情况,可能需要强制更新(绝大部分时候发生需要强制更新是因为自己设计错误,例如组件创建之后添加 data属性),此时,可以使用组件的实例方法 $forceUpdate 来迫使组件实例重新渲染。

另一种情形则恰恰相反,可能有一个包含很多很多静态内容的组件,你可以向根元素添加 v-once 指令来确保只求值一次并缓存起来,这样可以提高渲染速度(只有在内容的确是静态且渲染速度不够理想时才考虑这种边界处理策略)。

无论强制更新或者单次渲染求值,都是应该尽量避免的,它们存在只是一种弥补机制。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 16:39:54  更:2021-12-02 16:40:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:33:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码