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

相关推荐
正小安1 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光3 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   3 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   3 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web3 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常3 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇4 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr4 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho5 小时前
【TypeScript】知识点梳理(三)
前端·typescript