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.内联模板

相关推荐
深度混淆几秒前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China1 分钟前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q2 分钟前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海3 分钟前
Chrome离线安装包下载
前端·chrome
m512713 分钟前
LinuxC语言
java·服务器·前端
Myli_ing1 小时前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维1 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
雯0609~2 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ2 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z2 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript