当前位置: 首页 > news >正文

Vue 3 魔法揭秘:CSS 解析与 scoped 背后的奇幻之旅

文章目录

    • 一、背景
    • 二、源码分析
      • transformMain 返回值
      • transformStyle 方法
      • compileStyleAsync 方法
      • scopedPlugin 方法
      • template 添加 __scopeId
    • 三、总结

一、背景

Vue 3 文件编译流程详解与 Babel 的使用

上文分析了 vue3 的编译过程,但是在对其中样式的解析遗留了一些问题:

  • 为什么 genStyleCode 得到了 import 语句 ?我们真正的代码是怎么转化的?
  • 平时vue scoped是怎么实现样式隔离的?
  • 如下图标签/选择器上的唯一属性怎么加上去的?

在这里插入图片描述

带着这些疑问继续进行源码解析。

二、源码分析

书接上回我们发现了 transformMain 方法中 genStyleCode 会处理我们的为import "/Users/zcy/Desktop/毕设/smart-port/src/App.vue?vue&type=style&index=0&lang.less" 那是怎么翻译成具体的 css 的呢 ?

在这里插入图片描述

transformMain 返回值

我们先看一下 transformMain 方法把转码转化为了什么? 下面是转化后格式化完成后的代码:

// 源码script部分
import { ref } from 'vue'; const _sfc_main = {setup(__props, { expose }) {expose(); const state = ref(1)const __returned__ = { state, ref }Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })return __returned__}
}
import {resolveComponent as _resolveComponent, createVNode as _createVNode, toDisplayString as _toDisplayString,createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock,createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId
} from "vue"
const _withScopeId = n => (_pushScopeId("data-v-7ba5bd90"), n = n(), _popScopeId(), n)
const _hoisted_1 = { id: "nav" }
// 源码template部分
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {const _component_router_link = _resolveComponent("router-link")const _component_router_view = _resolveComponent("router-view")return (_openBlock(),_createElementBlock(_Fragment, null,[_createElementVNode("div", _hoisted_1,[_createVNode(_component_router_link, { to: "/login" }),_createVNode(_component_router_link, { to: "/" }),_createElementVNode("div", null, _toDisplayString($setup.state), 1 /* TEXT */)]),_createVNode(_component_router_view)], 64 /* STABLE_FRAGMENT */))
}// 源码样式部分
import "/Users/zcy/Desktop/毕设/smart-port/src/App.vue?vue&type=style&index=0&scoped=true&lang.less"_sfc_main.__hmrId = "7ba5bd90"
typeof __VUE_HMR_RUNTIME__ !== 'undefined' && __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main)
import.meta.hot.accept(({ default: updated, _rerender_only }) => { if (_rerender_only) { __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render) } else { __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated) } })
import _export_sfc from 'plugin-vue:export-helper'
export default /*#__PURE__*/_export_sfc(_sfc_main, [['render', _sfc_render], ['__scopeId', "data-v-7ba5bd90"], ['__file', "/Users/zcy/Desktop/毕设/smart-port/src/App.vue"]])

上面这段代码核心三部分 _sfc_render、 styles,_sfc_main,可以看到这里对样式的解析其实只转化为了一个 import 方法,那是怎么会转化真正的 css 的呢 ?这个时候我们在回到 vuePlugin 入口处的 transform 方法中,如下图:

在这里插入图片描述

transformStyle 方法

从上图中可以看在 vue 不存在的时候会进入 transformMain ,否则会进入到 elsetransformStyle 方法,从名字就可以看出这个转化样式的过程,因此我们放开 transformMain 的断点,在 transformStyle 打上断点并进入该方法。

在这里插入图片描述

compileStyleAsync 方法

进入到改方法后我们可以看到内部在执行了 compileStyleAsync 方法, 之后样式就已经加上了隔离,由 #app -> #app[data-v-7ba5bd90], 因此我们深入一下 options.compiler.compileStyleAsync 这个方法,根据我们上一篇文得知,这个方法是在 vue/compiler-sfc 核心包中,我们打个断点进入该方法。

在这里插入图片描述

compileStyleAsync 执行了 doCompileStyle ,接下来我简单摘要一下这个方法:

function doCompileStyle(options) {const { filename, id, scoped = false, trim = true, isProd = false, modules = false, modulesOptions = {}, preprocessLang, postcssOptions, postcssPlugins } = options;// scoped id 来自于 descriptor.idconst shortId = id.replace(/^data-v-/, '');const longId = `data-v-${shortId}`;// 插件数组const plugins = (postcssPlugins || []).slice();plugins.unshift(cssVarsPlugin({ id: shortId, isProd }));// scoped 存在则加入改插件if (scoped) {plugins.push(scopedPlugin(longId));}let result;let code;try {// postcss 处理这些插件result = _postcss__default(plugins).process(source, postCSSOptions);// In async mode, return a promise.if (options.isAsync) {return result.then(result => ({code: result.css || '',// xxx}))}code = result.css;}return {code: code || ``,map: outMap && outMap.toJSON(),// xxxx};
}

scopedPlugin 方法

这边可以看到使用了 postcss 加载各种插件,其中就有 scopedPlugin ,顾名思义就是给我添加样式隔离的,接下来我们进入这个方法看一眼:

在这里插入图片描述
在这里插入图片描述

  • scopedPlugin 中的 Rule 配置会调用 processRule 方法并传入 scopedId
  • processRule 方法会遍历每个选择器进行执行 rewriteSelector 操作
  • rewriteSelector 方法会处理 v-deep、 >>>、 /deep/、等特殊操作符,最后加上 给选择器加上 scopedId 属性

如上图所示会在该方法中对 css 选择器加上隔离 __scopeId

template 添加 __scopeId

选择器的样式加上了 那我们 template 中的属性什么时候加上呢?

在这里插入图片描述

回到我们最开始 transformMain 中 返回的 code 当中,我们可以看到源码的 template 转化为了 render 函数,并且传入了 __scopeId 我们不难猜到肯定会在 调用 _createElementBlock 等方法的时候会转化为 vdom,最后更新到 dom 属性中, 对于 vdom 的转化过程本文就不过多深入。

三、总结

从上文可以发现 vue3css 的解析其实是分为两次:

  • 第一次先通过 transformMain 得到 import 'xxxx.vue?xxxx' 的方法
  • 第二次因为新增了import 语句插件又会重新执行,再次执行因为 vue 已经存在了,则会进入 transformStyle 方法,在里面进行具体解析,包含 scoped 等各种插件配合使用解析为最终 css 文件。

相关文章:

Vue 3 魔法揭秘:CSS 解析与 scoped 背后的奇幻之旅

文章目录 一、背景二、源码分析transformMain 返回值transformStyle 方法compileStyleAsync 方法scopedPlugin 方法template 添加 __scopeId 三、总结 一、背景 Vue 3 文件编译流程详解与 Babel 的使用 上文分析了 vue3 的编译过程,但是在对其中样式的解析遗留了一…...

如何获取钉钉webhook

第一步打开钉钉并登录 第二步创建团队 并且 添加自定义 机器人 即可获取webhook...

网页WebRTC电话和软电话哪个好用?

关于WebRTC电话与软件电话哪个更好用,这实际上取决于多个因素,并没有一个绝对的答案。不过,我可以根据WebRTC技术的一些特点,以及与传统软件电话相比的优劣势,为你提供一个清晰的对比。 首先,让我们了解一下…...

MySQL Mail服务器集成:如何配置发送邮件?

MySQL Mail插件使用指南?怎么优化 MySQL发邮件性能? MySQL Mail服务器的集成,使得数据库可以直接触发邮件发送,极大地简化了应用架构。AokSend将详细介绍如何配置MySQL Mail服务器,以实现邮件发送功能。 MySQL Mail&…...

【Rockchip系列】官方函数:imcopy

imcopy 函数原型 IM_STATUS imcopy(const rga_buffer_t src,rga_buffer_t dst,int sync 1,int *release_fence_fd NULL);功能说明 imcopy函数用于执行单次快速图像拷贝操作,将图像从源缓冲区拷贝到目标缓冲区。 参数说明 参数描述src[必填] 源图像缓冲区&…...

Matlab实现鲸鱼优化算法优化回声状态网络模型 (WOA-ESN)(附源码)

目录 1.内容介绍 2部分代码 3.实验结果 4.内容获取 1内容介绍 鲸鱼优化算法(Whale Optimization Algorithm, WOA)是一种基于座头鲸捕食行为的群智能优化算法。该算法通过模仿座头鲸使用螺旋形路径和包围猎物的策略来探索和开发解空间,以找到…...

迈威通信闪耀工博会,以创新科技赋能工业自动化

昨日,在圆满落幕的第24届中国国际工业博览会上,迈威通信作为工业自动化与智慧化领域的先行者,以“创新打造新质通信,赋能工业数字化”为主题精彩亮相,向全球业界展示了我们在工业自动化领域的最新成果与创新技术。此次…...

C# DotNetty客户端

1. 引入DotNetty包 我用的开发工具是VS2022,不同工具引入可能会有差异 工具——>NuGet包管理器——>管理解决方案的NuGet程序包 搜索DotNetty 2.新建EchoClientHandler.cs类 用于接收服务器返回数据 public class EchoClientHandler : SimpleChannelIn…...

4G模组SIM卡电路很简单,但也要注意这些坑

上次水SIM卡相关的文章,还是上一次; 上一篇文章里吹牛说,跟SIM卡相关的问题还有很多,目的是为下一篇文章埋下伏笔;伏笔埋是埋下了,但如果债老是不还,心里的石头就总悬着,搞不好老板…...

常见电脑品牌BIOS设置与进入启动项快捷键

常见电脑品牌BIOS与引导项快捷键速查表 | 电脑品牌 | BIOS快捷键 | 引导项快捷键 | 备注 ||------------|------------|--------------|------------------------------ || 联想 | F2/F1 | F12 | 笔记本通常为F2,台式机通常为F1 || IBM/ThinkPad | F1 | 未知 | ||…...

C语言中的日志机制:打造全面强大的日志系统

前言 在软件开发中,良好的日志记录机制对于调试、监控程序状态和维护系统的稳定性至关重要。本文将介绍如何在C语言中构建一个全面强大的日志系统,并提供一些示例代码。 1. 日志的基本概念 日志级别:用于分类日志信息的重要性,…...

局域网广域网,IP地址和端口号,TCP/IP 4层协议,协议的封装和分用

前言 在古老的年代,如果我们要实现两台机器进行数据传输, A员工就得去B员工的办公电脑传数据(B休息,等A传完),这样就很浪费时间 所以能不能不去B的工位的同时,还能传数据。这时候网络通信就出来…...

LabVIEW项目编码器选择

在LabVIEW项目中,选择增量式(Incremental Encoder)和绝对式(Absolute Encoder)编码器取决于项目的具体需求。增量式编码器和绝对式编码器在工作原理、应用场景、精度和成本等方面存在显著差异。以下从多方面详细阐述两…...

Spring Boot实现房产租赁业务逻辑

1 绪论 1.1 研究背景 中国的科技的不断进步,计算机发展也慢慢的越来越成熟,人们对计算机也是越来越更加的依赖,科研、教育慢慢用于计算机进行管理。从第一台计算机的产生,到现在计算机已经发展到我们无法想象。给我们的生活改变很…...

汽车3d动画渲染选择哪个?选择最佳云渲染解决方案

面临汽车3D动画渲染挑战?选择正确的云渲染服务至关重要。探索最佳解决方案,优化渲染效率,快速呈现逼真动画。 汽车3d动画渲染选择哪个? 对于汽车3D动画渲染,选择哪个渲染器取决于你的项目需求、预算和期望的效果。Ble…...

火语言RPA流程组件介绍--网页/元素截图

🚩【组件功能】:对整个网页、可见区域或者某个元素进行截图 ,保存至指定文件夹,仅适用于内置浏览器 配置预览 配置说明 截图类型 整个网页/可见区域/元素截图 目标元素 支持T或# 通过自动捕获工具捕获(选择元素工具使用方法)…...

VSCode编程配置再次总结

VScode 中C++编程再次总结 0.简介 1.配置总结 1.1 launch jsion文件 launch.json文件主要用于运行和调试的配置,具有程序启动调试功能。launch.json文件会启用tasks.json的任务,并能实现调试功能。 左侧任务栏的第四个选项运行和调试,点击创建launch.json {"conf…...

银行管理系统

摘 要 伴随着信息技术与互联网技术的不断发展,人们进到了一个新的信息化时代,传统管理技术性没法高效率、容易地管理信息内容。为了实现时代的发展必须,提升管理高效率,各种各样管理管理体系应时而生,各个领域陆续进到…...

极狐GitLab 17.4 重点功能解读【四】

GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...

[每日一练]利用自连接实现数量查询

该题目来源于力扣: 1731. 每位经理的下属员工数量 - 力扣(LeetCode) 题目要求: 表:Employees----------------------- | Column Name | Type | ----------------------- | employee_id | int | | name …...

Linux云计算 |【第四阶段】RDBMS1-DAY3

主要内容: 子查询(单行单列、多行单列、单行多列、多行多列)、分页查询limit、联合查询union、插入语句、修改语句、删除语句 一、子查询 子查询就是指的在一个完整的查询语句之中,嵌套若干个不同功能的小查询,从而一…...

初始MYSQL数据库(8)—— JDBC编程

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: MYSQL 目录 JDBC的概念 JDBC的使用 加载驱动包 建立连接 创建 statement 对象 定义并执行SQL语句 处理结果集 关闭资源 SQL注入 …...

Vue $router.push打开新窗口

Vue $router.push打开新窗口 最近有粉丝小伙伴问我:$router.push方法用于在当前窗口中跳转路由,但有时候我们需要在新的窗口或标签页中打开一个路由改怎么实现呢? 那么这里就介绍下实现逻辑和代码案例! 文章目录 Vue $router.pus…...

SQL进阶技巧:如何利用if语句简化where或join中的条件 | if条件语句的优雅使用方法

目录 0 问题场景 1 数据准备 2 问题分析 2.1 需求一 2.2需求二 3 小结 0 问题场景 有两张表,一张用户下单表user_purchase(用户ID粒度)包含用户ID、订单ID和下单消耗金额和一张用户维表user_info包含用户ID、用户年龄和用户是否实名认证。 user_purchase user_info 需…...

SpringCloud-Alibaba第二代微服务快速入门

1.简介 Spring Cloud Alibaba其实是阿里的微服务解决方案,是阿里巴巴结合自身微服务实践,开源的微服务全家桶,在Spring Cloud项目中孵化成为Spring Cloud的子项目。第一代的Spring Cloud标准中很多组件已经停更,如:Eureak,zuul等。所以Sprin…...

JSON字符串转换成对象

在Java中,将JSON字符串转换成对象是一个常见的操作,特别是在处理Web服务或API时。这通常通过使用第三方库来实现,因为Java标准库(Java SE)本身并不直接支持JSON的序列化和反序列化。最常用的库之一是Jackson和Gson。下…...

第三十五章 结合加密和签名

文章目录 第三十五章 结合加密和签名使用非对称密钥签名并加密使用非对称密钥加密并签名 第三十五章 结合加密和签名 可以在同一条消息中加密和签名。在大多数情况下,只需组合前面主题中给出的方法即可。本主题讨论了多种场景。 使用非对称密钥签名并加密 要签名…...

FastAPI 第八课 -- 路径操作依赖项

目录 一. 前言 二. 依赖项(Dependencies) 2.1. 依赖注入 2.2. 依赖项的使用 三. 路径操作依赖项的基本使用 3.1. 预处理(Before) 3.2. 后处理(After) 四. 多个依赖项的组合 五. 异步依赖项 一. 前…...

大厂面试真题-说一下Mybatis的缓存

首先看一下原理图 Mybatis提供了两种缓存机制:一级缓存(L1 Cache)和二级缓存(L2 Cache),旨在提高数据库查询的性能,减少数据库的访问次数。注意查询的顺序是先二级缓存,再一级缓存。…...

jQuery UI 工作原理

jQuery UI 工作原理 引言 jQuery UI 是建立在 jQuery 库之上的一个开源 JavaScript 库,它提供了一系列用户界面交互、特效、小部件和主题。它旨在简化 HTML 用户界面的开发,使开发者能够轻松地创建具有丰富交互性和视觉吸引力的网页。本文将深入探讨 jQuery UI 的工作原理,…...

网站授权系统怎么用/重庆seo搜索引擎优化优与略

目录一、简介二、验证性实验1)ipconfig2)ping3)tracert4)ARP5)DHCP6)netstat7)DNS8)cache一、简介 本计算机网络实验教程由验证性、Wireshark 和 Cisco Packet Tracer 实验等三个部…...

网站建设如何不被忽悠/各大网站收录查询

1.Intent:一个Intent就是对一次将要执行的操作的抽象描述 2.拨打电话,发送短信 3.启动新的Activity,传递参数和返回参数...

专门做淘宝代运营的网站/竞价推广招聘

配置PHP.ini 更改配置项&#xff08;必须&#xff09;auto_prepend_file "C:\xampp\htdocs\auto_prepend_file.php" 更改配置项&#xff08;可选&#xff09;allow_url_include On auto_prepend_file.php文件内容 <?php /*** 引入static文件* param {array|str…...

全屋设计的软件/广州seo做得比较好的公司

Java虚拟机运行时数据区 对象的创建 Java创建对象&#xff0c;在语言层面上使用new关键字。虚拟机遇到new关键字时&#xff0c;会检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有…...

阿旗建设局举报网站/学电脑培训班

今天在做搜索框的时候、遇到需要获取焦点之后做一些事情、实现方法也很简单、那就是绑定OnFocusChangeListener事件、实现 onFocusChange(View v, boolean hasFocus) 方法、第二个参数就是判断得到焦点或失去焦点、从而实现我得想要的效果、代码如下&#xff1a; EditText sear…...

批量导文章到wordpress/黄山seo公司

目前&#xff0c;******已成为一个很严重的网络问题。许多***甚至可以突破SSL加密和各种防火墙&#xff0c;攻入Web网站的内部&#xff0c;窃取信息。***可以仅凭借浏览器和几个技巧&#xff0c;即套取Web网站的客户信用卡资料和其它保密信息。因此&#xff0c;这无疑给网站建设…...