首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何解决--在渲染函数之外调用插槽的问题

如何解决--在渲染函数之外调用插槽的问题

作者头像
前端小智@大迁世界
发布于 2022-10-27 08:39:58
发布于 2022-10-27 08:39:58
5.7K00
代码可运行
举报
文章被收录于专栏:终身学习者终身学习者
运行总次数:0
代码可运行

更多开源作品请看 GitHub ,包含一线大厂面试完整考点、资料以及我的系列文章。

如果你是用 Vue 来开发项目的,那么,你曾经有可能访问 slot.default() 遇到如下问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Slot "default" invoked outside of the render function:
this will not track dependencies used in the slot. 
Invoke the slot function inside the render function instead. 

本文本中,将会解释这个错误背后的原因以及如何解决这个问题。

插槽的调用需要发生在渲染函数或模板中。要抑制这个错误,我们只需要把代码移到一个计算的属性或从模板或渲染函数中调用的方法中。

“this will not track dependencies used in the slot” 指的是什么?

错误信息解释了问题产生的本质原因,但这个提示不是很清晰,无法帮助我们界定问题的本质。下面,我们来详细介绍下错误背后的原因产生。

this will not track dependencies used in the slot.

经过一些调查,我做了一个可复现的代码,并理解了在渲染函数之外使用slots.default()语法的含义。为了理解这个问题,我们先复习一下 Vue 的响应式原理。

Vue 的响应式性系统允许我们声明属性、数据和计算属性,而不需要跟踪它们的变化。响应式性系统在幕后工作,确保我们的变量始终是最新的。

在Vue框架内,最常见的响应式特征的情况是使用 computed

计算属性指的是一个变量,它可以被用来以有效和响应式的方式修改和操作你的组件中的数据和属性。

计算属性的一个简单例子是博客片段,我们把一篇完整的博客文章作为属性传递,并把它截断成一定数量的字符。另一个更常见的例子是一个简单的变量,用来定义一个按钮的文本,根据当前的状态 "显示 "或 "隐藏"。

举例来说,在 "expanded"的值被改变之前,下面的属性将永远不会再被运行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const buttonText = computed( () => {
  return expanded.value ? 'Show less' : 'Show more';
});

除非 expanded 的值发生变化,否则上述方法不会再被触发。Vue 在幕后所做的观察 expanded 变量的工作就是所谓的 "跟踪依赖性"。

你可能已经意识到了,"跟踪依赖" 这几个字和Vue框架在试图访问插槽时产生的错误中提到的一样。事实上,这个错误是为了告诉我们,在渲染函数之外使用slots.default()的语法,会使变量失去响应性,因此它不会 "跟踪" 任何可能影响它的变化。

拿上面的例子来说,失去依赖关系的跟踪将意味着无论 expanded 的值是多少,按钮都不会改变。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 下面的代码只是为了说明问题
//  我们只是假设了一个具有跟踪依赖性的变量,这也是我们插槽发生的情况
const expanded = ref( false ); //Broken Tracking

console.log(buttonText)
// 输出 "Show more"

expanded.value = true;

console.log(buttonText)
// 输出: "Show more"  值没有没有改变,因为Vue无法跟踪 expanded 的变化。

在我们的代码库中,未被追踪的变量不是我们想要的东西,应该要尽量的避免它。

如何确保 Vue 插槽被跟踪依赖

接下来,我们分析下可以做些什么来确保我们的插槽有一个响应式的跟踪系统,确保不会更新失败

通过确保我们的槽调用发生在渲染函数和模板中,问题就可以解决了,正如错误信息中提到的那样。

Invoke the slot function inside the render function

我们现在要介绍两种不同的情况。第一种是在使用渲染函数时调用插槽函数,第二种是在使用vue单文件组件的<template>部分。

在渲染函数中使用插槽

当在一个有渲染函数的组件中使用插槽时,我们必须确保在渲染函数的 "return"语句中调用插槽函数,而不是在 setup 中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 不好
import { h } from 'vue'

export default {
  setup( props, { slots } ) {
    const defaultSlot = slots.default();
    return () => h('div', defaultSlot)
  }
}

// 好
import { h } from 'vue'

export default {
  setup( props, { slots } ) {
    return () => h('div', slots.default())
  }
}

在使用单一文件组件(SFC)时使用插槽

如果使用单文件组件并使用 <template> 块声明 HTML,你可能会认为不能直接访问渲染函数,但事实并非如此。

当我第一次遇到这个问题时,我花了一些时间试图了解如何在渲染函数中移动插槽函数,但在Spa 之后,我想起了 <template>标签是由编译器为我们转化成渲染函数的。

了解 <template> 块和渲染函数是等价的,对我们定义解决问题的方法有很大帮助。事实上,为了消除警告并确保在我们的组件中跟踪依赖关系,我们需要确保插槽的调用发生在HTML中(随后被框架编译成一个渲染函数)。

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 缺点 - 如插槽改变,它将不会改变
<template>
  <div :class="{ 'style-for-svg': isSvg }">
    <slot></slot>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup( props, { slots } ) {
    const isSvg = ref( false );

    if( slots.default()[0].type === 'svg' ) {
      isSvg.value = true;
    }

    return {
      isSvg
    }
  }
}
</script>


// 优点:插槽改变,跟着变化
<template>
  <div :class="{ 'style-for-svg': $slots.default()[0].type === 'svg' }">
    <slot></slot>
  </div>
</template>

<script>

export default {
  setup( ) {
  }
}
</script>

解决这个问题是很简单的。直接在模板中加入函数调用,就可以解决我们的问题了。不幸的是,上面的解决方案代码不够简洁。

那要怎么做呢?使用计算属性。

在调查过程中,计算属性也被编译为渲染函数的一部分,可以用来使代码更易读,并且仍然保持变量的响应式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div :class="{ 'style-for-svg': isSvg }">
    <slot></slot>
  </div>
</template>

<script>
import { computed } from 'vue'

export default {
  setup( ) {

    const isSvg = computed( () => {
      return slots.default()[0].type === 'svg';
    } );

    return {
       isSvg
    }

  }
}
</script>

总结

在开发Vue组件时,需要访问插槽函数的情况并不常见,但如果你需要这样做,我希望上面的解决方案能为你节省一些时间。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
25个 Vue 技巧,开发了5年了,才知道还能这么用
学习成为一个更好的Vue开发者并不总是关于那些需要花时间和精力才能掌握的大概念。掌握一些技巧和窍门,可以让我们的编程生活变得更容易--没有大量重复的工作。
@超人
2021/07/29
3.7K0
25个 Vue 技巧,开发了5年了,才知道还能这么用
Vue3, setup语法糖、Composition API全方位解读
支持绑定多个v-model,v-model 是 v-model:modelValue 的简写
yyds2026
2022/09/26
3.2K0
前端系列14集-Vue3-setup
页面浏览量(Page View,PV)和访客数(Unique Visitors,UV)
达达前端
2023/10/08
5700
前端系列14集-Vue3-setup
什么是作用域插槽?插槽与作用域插槽的区别
创建组件虚拟节点时,会将组件的儿子的虚拟节点保存起来。当初始化组件时,通过插槽属性将儿 子进行分类 {a:[vnode],b[vnode]}
全栈程序员站长
2022/09/20
1.5K0
什么是作用域插槽?插槽与作用域插槽的区别
vue2.0 插槽不是响应性的
项目中自定了组件 widget,作为容器,其中 header 部分做了预置插槽 slot,用于信息的展示;在实际使用过程中,header 内容需要根据不同条件展示不同信息。至此,问题出现了~~~
奋飛
2023/01/13
8770
vue2.0 插槽不是响应性的
Vue渲染函数该如何使用?有哪些需要注意的地方?
Vue的模板语法适用于绝大部分的需求场景(模板最终会被编译为渲染函数),在绝大多数情况下,Vue 推荐使用模板语法来创建应用。然而在某些使用场景下,我们真的需要用到 JavaScript 完全的编程能力,举例如下:
房东的狗丶
2023/02/17
6800
Vue最佳实践和实用技巧(下)
attrs还可与listeners搭配使用,listeners包含了父组件传递的事件(不包含.native修饰器),它可以通过v-on="
用户6256742
2024/05/18
2320
Vue2向Vue3过渡,持续记录
迁移指南:https://v3.cn.vuejs.org/guide/migration/introduction.html
房东的狗丶
2023/02/17
6.4K0
vue2升级vue3:Vue2/3插槽——vue3的jsx组件插槽slot怎么处理
vue 在 2.6 版本中,对插槽使用 v-slot 新语法,取代了旧语法的 slot 和 slot-scope,并且之后的 Vue 3.0 也会使用新语法,这并不是仅写法的不同,还包括了性能的提升
周陆军博客
2022/06/24
2.4K0
Vue3从入门到精通(三)
在 Vue3 中,插槽(Slots)的使用方式与 Vue2 中基本相同,但有一些细微的差异。以下是在 Vue3 中使用插槽的示例:
明志德道
2023/10/21
3800
Vue3 | Composition API 包括setup、ref等新特性详解 与 实战
使得相同的、相关的功能代码 可以比较 完整地聚合起来, 提高可维护性、可读性,提高开发效率; 规避 同一个功能的代码, 却散落在 组件定义中的data、methods、computed、directives、template、mixin等各处 的问题;
凌川江雪
2022/01/20
1.5K0
Vue3 | Composition API 包括setup、ref等新特性详解 与 实战
前端系列15集-watch,watchEffect,eventBus
watchEffect,它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
达达前端
2023/10/08
6060
Vue.js 中的无渲染行为插槽[每日前端夜话0xF7]
翻译:疯狂的技术宅 作者:David Desmaisons 来源:alligator
疯狂的技术宅
2019/12/11
1.6K0
前端系列13集-内置内容,单文件组件,进阶 API
在你的站点上动态渲染任意的 HTML 是非常危险的,因为它很容易导致 [XSS 攻击]。请只对可信内容使用 HTML 插值,绝不要将用户提供的内容作为插值
达达前端
2023/10/08
4390
前端面试5家公司,被经常问到的vue面试题
在HTML中 slot 元素 ,作为 Web Components 技术套件的一部分,是Web组件内的一个占位符
bb_xiaxia1998
2022/09/22
1.2K0
[day-ui] Alert 组件学习
从样式功能来看,整体不是很复杂,alert 组件主要包括了主题色,title,关闭按钮,关闭事件,居中,加粗等
测不准
2021/06/02
3.7K0
VUE3.0和VUE2.0语法上的不同
前言:本篇文章只做VUE3.0和VUE2.0语法上的不同分析,不做性能和源码架构等的分析。
javascript艺术
2022/06/08
1.6K0
VUE3.0和VUE2.0语法上的不同
Vue3.0 新特性以及使用变更总结(实际工作用到的)
Vue3.0 在去年9月正式发布了,也有许多小伙伴都热情的拥抱Vue3.0。去年年底我们新项目使用Vue3.0来开发,这篇文章就是在使用后的一个总结, 包含Vue3新特性的使用以及一些用法上的变更。
@超人
2021/03/23
2.6K0
Vue3.0 新特性以及使用变更总结(实际工作用到的)
Vue.js 源码分析—— Slots 是如何实现的
今天主要分析 Vue.js 中常用的 Slots 功能是如何设计和实现的。本文将分为普通插槽、作用域插槽以及 Vue.js 2.6.x 版本的 v-slot 语法三部分进行讨论。
前端黑板报
2021/07/23
2.7K0
Vue.js 源码分析—— Slots 是如何实现的
Vue 2 常见面试题速查
当一个 Vue 实例创建时,Vue 会遍历 data 中的属性,用 Object.defineProperty 将它们转为 getter / setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
Cellinlab
2023/05/17
1.2K0
Vue 2 常见面试题速查
推荐阅读
相关推荐
25个 Vue 技巧,开发了5年了,才知道还能这么用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验