Vue 2 处理边界情况

访问元素和组件

通过Vue 2 组件基础一文的学习,我们知道组件之间可以通过传递props事件来进行通信。

但在一些情况下,我们使用下面的方法将更有用。


1.访问根实例

根实例可通过this.$root获取。

我们在所有子组件中都可以像上面那样访问根实例,它就像一个vuex中的全局store

这样我们可以在根实例上定义方法和属性,这些方法和属性可以在所有组件中访问。

根实例也可以用作事件总线,你可以触发根实例上的自定义事件,在其他组件上监听这些事件以进行通信。一个示例如下:

html 复制代码
<!DOCTYPE html>
<html>

<head>
    <title>Vue 事件总线</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <button @click="sendMessage">Send Message By Root</button>
        <child-component></child-component>
    </div>
    <script>
        //  注册组件
        Vue.component('child-component', {
            data: function () {
                return {
                    childMessage:'childMsg'
                }
            },
            template: 
            `
            <div>
                <p>Message in ChildComponent:{{childMessage}}</p>
            </div>
            `,
            created(){
                //通过 this.$root 监听`message-sent`事件
                this.$root.$on('message-sent',message=>{
                    this.childMessage=message
                })
            }
        });
        var vm = new Vue({
            el: '#app',
            data:{
                message:'rootMsg'
            },
            methods:{
                sendMessage(){
                    //在根实例上触发自定义事件'message-sent'
                    this.$emit('message-sent',this.message)
                }
            }
        });
    </script>
</body>

</html>
<script>

2.访问父组件实例、访问子组件实例或子元素

之前我们可以通过传递prop来达到 子组件访问父组件实例 或者称为 父组件向子组件传值 的目的。

现在我们可以使用$parent property来访问父级组件实例。

之前我们也通过触发自定义事件传递抛出值的方式来访问子组件实例。

同样的,我们可以通过ref attribute为子组件或子元素添加一个ID引用。

html 复制代码
<child-component ref="child"></child-component>

于是可以使用this.$refs.child来访问子组件实例。

通过ref引用子组件示例:

html 复制代码
<!DOCTYPE html>
<html>

<head>
    <title>Vue ref 示例</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <button @click="toggleColor">Toggle Color</button>
        <p :style="{ color: textColor }">This text color can be toggled.</p>
        <child-component ref="childRef"></child-component>
    </div>
    <script>
        // 子组件
        Vue.component('child-component', {
            template:
                `
            <div>
                <p>This is a child component.</p>
            </div>
            `,
            methods: {
                sayHello() {
                    console.log('Hello from child component!');
                }
            }
        });

        var vm = new Vue({
            el: '#app',
            data: {
                textColor: 'black',
                isChildVisible: true
            },
            methods: {
                toggleColor() {
                    this.textColor = this.textColor === 'black' ? 'red' : 'black';
                    // 通过 ref 访问子组件实例中的方法
                    this.$refs.childRef.sayHello();
                }
            }
        });
    </script>
</body>

</html>

3.依赖注入

不管是this.$parentthis.$refs,都可能会陷入深层嵌套的风险,我们可能会通过this.$parent.$parent.$parent来访问上层某个组件实例。这无疑是不合理的。

针对较深层级的组件访问,Vue设计了依赖注入的模式。它允许我们将一个依赖注入到某个组件里,以便组件可以访问这个依赖而不需要显示传递它。这对于共享全局配置或服务非常有用,例如国际化(i18n)配置、数据请求服务等。

具体的,我们通过在父组件provide选项提供依赖,然后在子组件的inject选项注入依赖。

示例:

javascript 复制代码
//在父组件中
provide:{
	userSevice:new UserService()
}

//在子组件中
inject:['userService'],
created(){
    this.userService.doSomething()
}

为什么我们不使用$root实现这种方案呢?我认为,依赖注入适合小范围的配置共享,而全局共享则适用于$root

程序化的事件监听器

$emit触发的事件可以被v-on监听,但这不是我们这章的内容。

本文主要介绍 Vue 2 中程序化的事件监听器,我们可以使用它来动态地添加和删除事件监听器。

Vue实例上有一系列方法来处理事件,包括$on$once$off。它们都包含两个参数:eventNameeventHandler$on侦听一个事件;$once只侦听一个事件一次;$off停止侦听一个事件。

$emit$on$off浏览器的EventTarget API dispatchEventaddEventListenerremoveEventListener并不等同。

$emit用于触发自定义事件,dispatchEvent用于触发各种DOM事件。addEventListenerremoveEventListener同理。

循环引用

1.递归组件

我们可以在组件模板内部调用自身,这称为递归组件。递归组件要注意设置递归终止条件,例如v-if的值为false。

假设我们有一个表示文件夹结构的数据对象:

javascript 复制代码
<!DOCTYPE html>
<html>

<head>
    <title>Vue 2 递归组件 Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <recursive-folder :folder="folder"></recursive-folder>
    </div>
    <script>
        Vue.component('recursive-folder', {
            props: ['folder'],
            template: `
                <div>
                    <span>{{ folder.name }}</span>
                    <div v-if="folder.children.length > 0">
                        <ul>
                            <li v-for="childFolder in folder.children" :key="childFolder.name">
                                <recursive-folder :folder="childFolder"></recursive-folder>
                            </li>
                        </ul>
                    </div>
                </div>
            `
        });
        var vm = new Vue({
            el: '#app',
            name: 'recursive-folder',
            data: {
                folder: {
                    name: 'Folder A',
                    children: [
                        {
                            name: 'Subfolder A.1',
                            children: [
                                {
                                    name: 'File A.1.1',
                                    children: []
                                },
                                // 可能有更多子项
                            ]
                        },
                        {
                            name: 'File A.2',
                            children: []
                        },
                        // 可能有更多子项
                    ]
                }
            },
        });
    </script>
</body>

</html>

2.循环组件

++循环组件是不同组件互相使用,递归组件是自身使用自身++。

使用Vue.component全局注册组件时,Vue帮助我们自动解决组件之间的依赖关系,因此你可以随意使用它们。

但是,当我们使用模块系统(如Webpack)时,便可能出现循环依赖的情况。

为了解决该问题,你可以在组件的beforeCreate生命周期钩子函数中动态注册依赖组件,或者使用异步组件加载来确保组件能够正确解析和注册。

1)在组件的beforeCreate生命周期钩子函数中动态注册依赖组件:

javascript 复制代码
beforeCreate(){
    this.$options.components.AnotherComponent=require("./another-component.vue").default
}

2)使用异步组件加载:

参考Vue 2 动态组件和异步组件一文。


模板定义的替代品

1.内联模板

相关推荐
kyriewen1 小时前
百度用6%成本碾压硅谷?中国AI把性价比玩明白了
前端·百度·ai编程
kyriewen1 小时前
你还在手动敲命令部署?GitHub Actions 让你 push 即上线,摸鱼时间翻倍
前端·面试·github
Csvn3 小时前
Pinia 状态管理
前端
不减20斤不改头像3 小时前
手机一句话开发贪吃蛇!TRAE SOLO 移动端 AI 编程实测
前端·后端
xuankuxiaoyao3 小时前
Vue.js实践-组件基础下
前端·javascript·vue.js
一棵白菜4 小时前
Claude Code + Amazon Bedrock 使用指南
前端
大家的林语冰4 小时前
前端周刊:axios 疑遭朝鲜黑客“钓鱼“;CSS 新函数上线;npm 上线深色主题;Oxlint 兼容表;ESLint 支持 Temporal......
前端·javascript·css
哀木6 小时前
一个简单的套壳方案,就能让你的 Agent 少做重复初始化
前端
问心无愧05136 小时前
ctf show web入门27
前端
小村儿6 小时前
给 AI Agent 装上"长期记忆":Karpathy 的 LLM Wiki 思想,我做成了工具
前端·后端·ai编程