《Vuejs设计与实现》第 13 章(异步组件和函数式组件

目录

13.1 异步组件的问题与解决方法

13.2 异步组件的实现原理

3.2.1 封装 defineAsyncComponent 函数

13.2.2 超时与 Error 组件

13.2.3 延迟与 Loading 组件

13.2.4 重试机制

13.3 函数式组件

13.4 总结


在第12章,我们深入探讨了组件的基本含义和实现方式。而在本章,我们将重点关注异步组件和函数式组件两个关键概念。
异步组件的特性在于它可以异步地加载和渲染组件,这在进行代码分割或服务端下发组件时尤其重要。
另一方面,函数式组件则允许我们用一个普通函数定义组件,并以该函数的返回值作为组件的渲染内容。函数式组件特点在于无状态、简洁且直观。
虽然在 Vue2 中,函数式组件相比于有状态组件有明显的性能优势,但在 Vue3 中,这两者的性能差距已非常小。
如 Vue.js RFC 所言,我们在 Vue3 中使用函数式组件主要是因为其简单易用,而非性能优越。

13.1 异步组件的问题与解决方法

从核心角度看,用户完全可以自主实现异步组件,而无需依赖框架。例如,App 组件的同步渲染如下:

import App from 'App.vue'
createApp(App).mount('#app')

上述代码可以轻松地改为异步渲染:

const loader = () => import('App.vue')
loader().then(App => {createApp(App).mount('#app')
})

此处,我们使用 import() 动态加载组件,返回一个 Promise 实例。组件加载成功后,使用 createApp 函数挂载,实现页面的异步渲染。
如果我们想要部分页面异步渲染,我们只需能够异步加载某个组件。假设下面的代码是 App.vue 组件:

<template><CompA /><component :is="asyncComp" />
</template><script>import { shallowRef } from 'vue'import CompA from 'CompA.vue'export default {components: { CompA },setup() {const asyncComp = shallowRef(null)// 异步加载 CompB 组件import('CompB.vue').then(CompB => asyncComp.value = CompB)return {asyncComp}}}
</script>

此代码模板中,页面由同步渲染的 和动态组件构成,动态组件绑定了 asyncComp 变量。
脚本块异步加载 CompB 组件,加载成功后,设定 asyncComp 变量的值为 CompB,实现了 CompB 组件的异步加载和渲染。
虽然用户可以自定义异步组件,但其实现有复杂性,因为完整的异步组件设计包括以下考虑:

  1. 如果组件加载失败或超时,是否展示 Error 组件?
  2. 是否需要占位内容,例如 Loading 组件,于何时加载时展示?
  3. 是否设定延迟展示 Loading 组件的时间,避免由于组件加载过快导致的闪烁?
  4. 如果组件加载失败,是否需要重试?

为了更优雅地解决这些问题,我们需在框架层面为异步组件提供封装支持:

  1. 允许用户指定加载错误时的渲染组件。
  2. 允许用户指定 Loading 组件及其展示延迟。
  3. 允许用户设置组件加载超时时长。
  4. 提供组件加载失败后的重试功能。

总的来说,这些都是异步组件需要解决的核心问题

13.2 异步组件的实现原理

3.2.1 封装 defineAsyncComponent 函数

异步组件基于封装理念设计,其目标是提供易用的接口以减轻用户使用难度。参考以下用户代码示例:

<template><AsyncComp />
</template><script>
export default {components: {// 用 defineAsyncComponent 函数定义异步组件,接收一个加载器作为参数AsyncComp: defineAsyncComponent(() => import('CompA'))}
}
</script>

上述代码,通过 defineAsyncComponent 定义了异步组件,并在 components 组件选项中注册。
这样,异步组件可以像普通组件一样在模板中使用。这种使用 defineAsyncComponent 的方式比我们在 13.1 节中自行实现的异步组件更直观、简洁。

defineAsyncComponent 是一个高阶组件,它的基本实现如下:

function defineAsyncComponent(loader) {// 存储异步加载的组件的变量let InnerComp = null// 返回一个包装组件return {name: 'AsyncComponentWrapper',setup() {// 异步组件加载成功的标记const loaded = ref(false)// 执行加载器函数,返回一个 Promise 实例// 加载成功后,将组件赋值给 InnerComp,并将 loaded 标记为 trueloader().then(c => {InnerComp = cloaded.value = true})return () => {// 如果异步组件加载成功,则渲染该组件,否则渲染一个占位内容return loaded.value ? { type: InnerComp } : { type: Text, children: '' }}}}
}

关键点如下:

  1. defineAsyncComponent 本质是一个高阶组件,返回一个包装组件。
  2. 包装组件根据加载器的状态决定渲染内容。如果成功加载组件,渲染该组件;否则,渲染占位内容。
  3. 通常占位内容是注释节点。在组件未成功加载时,页面渲染一个注释节点作占位。但在这里,我们用一个空文本节点作为占位。
13.2.2 超时与 Error 组件

异步组件加载通常涉及网络请求,可能因网速慢导致加载时间过长,特别是在弱网环境下。
为了优化体验,我们可以允许用户设定超时时长。超过此时长仍未加载完成,则触发超时错误。如果用户配置了错误组件,此时则渲染错误组件。
为了实现这个功能,defineAsyncComponent 函数可以接受一个配置对象:

const AsyncComp = defineAsyncComponent({loader: () => import('CompA.vue'), // 指定异步组件的加载器timeout: 2000, // 设定超时时间(ms)errorComponent: MyErrorComp // 指定在发生错误时要渲染的组件
})

有了用户接口后,我们可以给出实现代码:

function defineAsyncComponent(options) {// options 可以是配置项,也可以是加载器if (typeof options === 'function') {// 如果 options 是加载器,则将其格式化为配置项形式options = {loader: options}}const { loader } = optionslet InnerComp = nullreturn {name: 'AsyncComponentWrapper',setup() {const loaded = ref(false)// 代表是否超时,默认为 false,即没有超时const timeout = ref(false)loader().then(c => {InnerComp = cloaded.value = true})let timer = nullif (options.timeout) {// 如果指定了超时时长,则开启一个定时器计时timer = setTimeout(() => {// 超时后将 timeout 设置为 truetimeout.value = true}, options.timeout)}// 包装组件被卸载时清除定时器onUmounted(() => clearTimeout(timer))// 占位内容const placeholder = { type: Text, children: '' }return () => {if (loaded.value) {// 如果组件异步加载成功,则渲染被加载的组件return { type: InnerComp }} else if (timeout.value) {// 如果加载超时,并且用户指定了 Error 组件,则渲染该组件return options.errorComponent ? { type: options.errorComponent } : placeholder}return placeholder}}}
}

关键点如下:

  • 异步加载是否超时由 timeout.value 标志。
  • 开始加载组件的同时,启动一个定时器进行计时。如果超时,将 timeout.value 设置为 true。当包装组件被卸载时,需要清除定时器。
  • 包装组件根据 loaded 和 timeout 的值来决定渲染内容。如果加载成功,渲染被加载的组件;如果超时并且用户指定了错误组件,渲染错误组件。

为了更全面地处理异步组件加载过程中的错误(超时只是其中一种),我们希望为用户提供以下能力:

  1. 当错误发生时,将错误对象作为错误组件的 props 传递,以便用户做进一步处理。
  2. 除了超时,还能处理其他原因导致的加载错误,例如网络失败等。

为了达到这两个目标,我们需要对代码进行一些调整:

function defineAsyncComponent(options) {if (typeof options === 'function') {options = {loader: options}}const { loader } = optionslet InnerComp = nullreturn {name: 'AsyncComponentWrapper',setup() {const loaded = ref(false)// 定义 error,当错误发生时,用来存储错误对象const error = shallowRef(null)loader().then(c => {InnerComp = cloaded.value = true})// 添加 catch 语句来捕获加载过程中的错误.catch(err => (error.value = err))let timer = nullif (options.timeout) {timer = setTimeout(() => {// 超时后创建一个错误对象,并复制给 error.valueconst err = new Error(`Async component timed out after ${options.timeout}ms.`)error.value = err}, options.timeout)}const placeholder = { type: Text, children: '' }return () => {if (loaded.value) {return { type: InnerComp }} else if (error.value && options.errorComponent) {// 只有当错误存在且用户配置了 errorComponent 时才展示 Error 组件,同时将 error 作为 props 传递return { type: options.errorComponent, props: { error: error.value } }} else {return placeholder}}}}
}

上述代码,我们添加了对加载过程中的错误捕获。当加载超时时,我们创建一个新的错误对象。
在渲染组件时,如果存在 error.value 并且用户配置了错误组件,就直接渲染错误组件并将 error.value 传递作为 props。
这样,用户可以在他们的错误组件中接收错误对象,从而实现更精细的错误处理。

13.2.3 延迟与 Loading 组件

异步加载的组件因网络因素影响,加载速度可能较慢或非常快。
在网络环境良好的情况下,异步组件可能很快加载,这可能导致 Loading 组件刚出现就立即消失,导致页面闪烁,这对用户体验来说是不好的。
我们可以通过设置延迟展示 Loading 组件的时间来解决这个问题,比如在超过 200ms 后才展示 Loading 组件。以下是这种策略的实现方法。
首先,定义异步组件时,我们添加 delay 和 loadingComponent 两个选项:

defineAsyncComponent({loader: () => new Promise(r => { /* ... */ }),delay: 200, // 延迟 200ms 展示 Loading 组件loadingComponent: { // Loading 组件setup() {return () => {return { type: 'h2', children: 'Loading...' }}}}
})

然后在 defineAsyncComponent 函数中实现这两个选项:

function defineAsyncComponent(options) {if (typeof options === 'function') {options = {loader: options}}const { loader } = optionslet InnerComp = nullreturn {name: 'AsyncComponentWrapper',setup() {const loaded = ref(false)const error = shallowRef(null)// 一个标志,代表是否正在加载,默认为 falseconst loading = ref(false)let loadingTimer = null// 如果配置项中存在 delay,则开启一个定时器计时,当延迟到时后将 loading.value 设置为 trueif (options.delay) {loadingTimer = setTimeout(() => {loading.value = true}, options.delay)} else {// 如果配置项中没有 delay,则直接标记为加载中loading.value = true}loader().then(c => {InnerComp = cloaded.value = true}).catch(err => (error.value = err)).finally(() => {loading.value = false// 加载完毕后,无论成功与否都要清除延迟定时器clearTimeout(loadingTimer)})let timer = nullif (options.timeout) {timer = setTimeout(() => {const err = new Error(`Async component timed out after ${options.timeout}ms.`)error.value = err}, options.timeout)}const placeholder = { type: Text, children: '' }return () => {if (loaded.value) {return { type: InnerComp }} else if (error.value && options.errorComponent) {return { type: options.errorComponent, props: { error: error.value } }} else if (loading.value && options.loadingComponent) {// 如果异步组件正在加载,并且用户指定了 Loading 组件,则渲染 Loading 组件return { type: options.loadingComponent }} else {return placeholder}}}}
}

关键改动:

  • 新增了一个状态 loading,代表是否正在加载。
  • 如果用户设置了 delay,则在该延迟时间后,如果仍未加载完成,就将 loading 设置为 true。
  • 不论加载是否成功,都要将 loading 设置为 false,并清除定时器。
  • 在渲染函数中,如果正在加载且用户设置了 loadingComponent ,就渲染该组件。

此外,我们需要支持 loadingComponent 的卸载。因此需要更新 unmount 函数,使其能够卸载组件实例的渲染内容(即 subTree ):

function unmount(vnode) {if (vnode.type === Fragment) {vnode.children.forEach(c => unmount(c))return} else if (typeof vnode.type === 'object') {// 对于组件的卸载,本质上是卸载其所渲染的内容unmount(vnode.component.subTree)return}const parent = vnode.el.parentNodeif (parent) {parent.removeChild(vnode.el)}
}

组件的卸载,本质上是要卸载组件所渲染的内容,即 subTree。
所以在上面的代码中,我们通过组件实例的 vnode.component 属性得到组件实例,再递归地调用 unmount 函数完成 vnode.component.subTree 的卸载。

13.2.4 重试机制

重试机制在异步操作(如网络请求)中非常常见。当异步加载组件失败,尤其是在网络不稳定的情况下,我们希望提供一种方式让加载操作可以自动重试,这有助于提升用户体验。

首先,我们创建一个模拟网络请求的 fetch 函数,该函数在1秒后返回一个错误。

function fetch() {return new Promise((resolve, reject) => {// 请求在1秒后失败setTimeout(() => {reject('err')}, 1000);})
}

接着,创建一个 load 函数来实现请求失败后的重试:

function load(onError) {const p = fetch() // 发起请求,得到 Promise 实例return p.catch(err => {return new Promise((resolve, reject) => {const retry = () => resolve(load(onError)) // 重试const fail = () => reject(err) // 失败onError(retry, fail) // 当错误发生时,调用 onError 回调})})
}

用户可以使用 load 函数进行资源加载,并在发生错误时重试:

load((retry) => {retry() // 失败后重试}
).then(res => {console.log(res) // 成功
})

最后,我们可以将这个重试机制应用到异步组件加载中

function defineAsyncComponent(options) {if (typeof options === 'function') {options = {loader: options}}const { loader } = optionslet InnerComp = null// 记录重试次数let retries = 0// 封装 load 函数用来加载异步组件function load() {return (loader()// 捕获加载器的错误.catch(err => {// 如果用户指定了 onError 回调,则将控制权交给用户if (options.onError) {// 返回一个新的 Promise 实例return new Promise((resolve, reject) => {// 重试const retry = () => {resolve(load())retries++}// 失败const fail = () => reject(err)// 作为 onError 回调函数的参数,让用户来决定下一步怎么做options.onError(retry, fail, retries)})} else {throw error}}))}return {name: 'AsyncComponentWrapper',setup() {const loaded = ref(false)const error = shallowRef(null)const loading = ref(false)let loadingTimer = nullif (options.delay) {loadingTimer = setTimeout(() => {loading.value = true}, options.delay)} else {loading.value = true}// 调用 load 函数加载组件load().then(c => {InnerComp = cloaded.value = true}).catch(err => {error.value = err}).finally(() => {loading.value = falseclearTimeout(loadingTimer)})// 省略部分代码}}
}

这段代码与接口请求的重试机制很类似。在异步组件加载过程中,如果加载失败,我们提供一个新的 Promise 实例,并将重试(retry)和失败(fail)的处理函数作为 onError 回调的参数,让用户决定下一步怎么做。

13.3 函数式组件

函数式组件简单易实现,其本质是一个返回虚拟 DOM 的函数。
在 Vue3 中,函数式组件的优点主要在于其简洁性,而非性能。即使是有状态组件,在 Vue3 中,其初始化的性能消耗也相对较低。
定义函数式组件如下:

function MyFuncComp(props) {return { type: 'h1', children: props.title }
}// 定义 props
MyFuncComp.props = {title: String
}

函数式组件无自身状态,但仍能接收外部传入的 props。对于 props 的定义,我们在组件函数上添加静态的 props 属性。
我们可以复用 mountComponent 函数来实现函数式组件的挂载,此外需要支持函数类型的 vnode.type。这可以在 patch 函数内实现:

function patch(n1, n2, container, anchor) {if (n1 && n1.type !== n2.type) {unmount(n1)n1 = null}const { type } = n2if (typeof type === 'string') {// 省略部分代码} else if (type === Text) {// 省略部分代码} else if (type === Fragment) {// 省略部分代码} else if (// type 是对象 --> 有状态组件// type 是函数 --> 函数式组件typeof type === 'object' ||typeof type === 'function') {// componentif (!n1) {mountComponent(n2, container, anchor)} else {patchComponent(n1, n2, anchor)}}
}

vnode.type 的类型用以判断组件类型:对象类型表示有状态组件,函数类型则表示函数式组件。
不论是哪种类型,都可以通过 mountComponent 完成挂载和通过 patchComponent 完成更新。
函数式组件的挂载可以在 mountComponent 函数中实现:

function mountComponent(vnode, container, anchor) {// 检查是否是函数式组件const isFunctional = typeof vnode.type === 'function'let componentOptions = vnode.typeif (isFunctional) {// 如果是函数式组件,则将 vnode.type 作为渲染函数,将 vnode.type.props 作为 props 选项定义componentOptions = {render: vnode.type,props: vnode.type.props}}// 省略部分代码
}

在 mountComponent 函数内,如果组件类型是函数式组件,则直接将组件函数作为组件选项对象的 render 选项,同时将组件函数的静态 props 属性作为组件的 props 选项。
从这里可以看出,由于函数式组件无需初始化 data 和生命周期钩子,其初始化性能消耗会比有状态组件少

13.4 总结

本章首先深入探讨了异步组件的作用和需求。异步组件在提高页面性能、进行包裹分解和服务端下发组件等场景中发挥了重要作用。尽管异步组件的实现可以完全在用户层面完成,但为考虑到加载失败、加载中的显示、超时设定以及重试机制等复杂问题,框架的内置支持成为了必要。因此,Vue3 提供了 defineAsyncComponent 函数来定义异步组件。
我们接着讨论了异步组件加载超时和加载错误的处理。通过给 defineAsyncComponent 函数指定参数,我们可以设置超时时间并指定错误发生时展示的组件。
考虑到网络状况的不稳定,加载异步组件可能耗时较长。为了提供更好的用户体验,我们需要在加载时展示 Loading 组件。同时,我们提供了 loadingComponent 选项和 delay 选项,允许用户自定义 Loading 组件并设置展示的延迟时间,避免 Loading 组件的闪烁问题。
在面对加载错误时,我们设计了重试机制。这种处理方式与处理接口请求错误时的重试机制相似。
最后,我们讨论了函数式组件。它只是一个返回虚拟 DOM 的函数,它的实现可以复用有状态组件的逻辑。对于函数式组件,我们在主函数上添加静态 props 属性来定义 props。同时,由于函数式组件无状态且无生命周期概念,我们在初始化函数式组件时选择性地复用有状态组件的初始化逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92392.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python的七大框架对比分析

谈到“Python 七大框架”时&#xff0c;通常指 Django、Flask、FastAPI、Tornado、Sanic、AIOHTTP 和 Pyramid 这七位“常驻嘉宾”。它们各有气质&#xff0c;适合的场景也截然不同。1. DjangoDjango 像一辆全副武装的重型越野&#xff1a;出厂就配好 ORM、后台管理、权限、缓存…

Redis中String数据结构为什么以长度44为embstr和raw实现的分界线?

​ 一道常见Redis面试题。 ​ 在Redis的String数据结构中&#xff0c;当字符串的实际长度小于44且包含非整数字符时底层编码方式为embstr。当超过44时使用raw底层编码方式。 ​ 那么为什么要以字符串的长度44为分界线呢&#xff1f; 信息一 ​ 首先要分析embst…

告别人工巡查,校园空调管理迈入智能物联高效时代

在“双碳”战略深入推进和智慧校园建设加速落地的背景下&#xff0c;学校空调的用电管理已经不再是“开与关”的简单问题&#xff0c;而是涵盖了能效优化、安全保障、智慧化管理的综合课题。蓝奥声科技凭借LPIOT低功耗物联网、ECWAN边缘协同网络等优势技术&#xff0c;打造出面…

Access开发右下角浮窗提醒

Hi&#xff0c;大家好呀&#xff01;感觉又有很长一段时间没有给大家更新内容了&#xff0c;最近一直在忙&#xff0c;给大家承诺的框架、视频教程、直播等等感觉又要跳票了&#xff0c;嘿嘿&#xff0c;但大家还是不要急&#xff0c;莫催我&#xff0c;我会慢慢都更新出来的&a…

AI自进化,GPU性能翻三倍——CUDA-L1开启自动优化新范式

最近看到一篇让我挺震撼的文章&#xff0c;来自 DeepReinforce 团队发布的一个新框架——CUDA-L1。说实话&#xff0c;刚看到标题说“AI 让 GPU 性能提升 3 倍以上”&#xff0c;我心里是有点怀疑的。毕竟我们搞科研的都知道&#xff0c;这种宣传语很多时候水分不小。但当我静下…

深入理解 Java AWT Container:原理、实战与性能优化

以 Container 为核心梳理 AWT 容器体系与事件模型&#xff0c;提供可运行的纯 AWT 示例&#xff08;含 Panel、Frame、Dialog、ScrollPane 正确用法&#xff09;&#xff0c;并给出常见问题与性能优化建议。 Java AWT, Container, 容器, 布局管理器, 事件驱动, ScrollPane, 性…

redis--黑马点评--用户签到模块详解

用户签到假如我们使用一张表来存储用户签到信息&#xff0c;其结构应该如下&#xff1a;CREATE TABLE tb_sign (id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 主键,user_id bigint unsigned NOT NULL COMMENT 用户id,year year NOT NULL COMMENT 签到的年,month tinyin…

Shell、Python对比

在 Shell 脚本&#xff08;sh/bash&#xff09; 和 Python 之间选择时&#xff0c;主要取决于具体的使用场景和需求。以下是两者的对比分析&#xff0c;帮助你判断哪种更方便&#xff1a;1. Shell 脚本&#xff08;sh/bash&#xff09;的优势适用场景系统管理任务&#xff1a;如…

自适应反步控制:理论与设计

自适应反步控制 文章目录自适应反步控制1. 基本思想A. 第一步B. 第二步1. 基本思想 基于传统反步法&#xff0c;考虑了系统方程中以线性形式出现的未知参数。核心思想包括参数估计率和控制率。 考虑二阶系统&#xff1a; {x˙1x2φ1T(x1)θx˙2uφ2T(x1,x2)θ(1)\begin{cases…

[Oracle] LEAST()函数

LEAST() 是 Oracle 中一个非常有用的函数&#xff0c;用于从一组表达式中返回最小值LEAST()函数会从给定的参数列表中返回最小的值&#xff0c;它与GREATEST()函数正好相反语法格式LEAST(expr1, expr2 [, expr3, ...])参数说明expr1, expr2, ...&#xff1a;要比较的表达式(至少…

SVM算法实战应用

目录 用 SVM 实现鸢尾花数据集分类&#xff1a;从代码到可视化全解析 一、算法原理简述 二、完整代码实现 三、代码解析 1. 导入所需库 2. 加载并处理数据 3. 划分训练集和测试集 4. 训练 SVM 模型 5. 计算决策边界参数 6. 生成决策边界数据 7. 绘制样本点 8. 绘制…

深度虚值期权合约有什么特点?

本文主要介绍深度虚值期权合约有什么特点&#xff1f;深度虚值期权合约是期权市场中一类特殊且风险收益特征鲜明的合约&#xff0c;其核心特点可归纳为以下六点。深度虚值期权合约有什么特点&#xff1f;一、定义&#xff1a;执行价与标的价差距极大深度虚值期权是指执行价&…

(LeetCode 面试经典 150 题) 86. 分隔链表(链表+双指针)

题目&#xff1a;86. 分隔链表 思路&#xff1a;双指针&#xff0c;时间复杂度0(n)。 双指针来维护小于x的链表和不小于x的链表即可&#xff0c;后面将两个链表连起来即可。 C版本&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* …

安全扫描:检测到目标站点存在javascript框架库漏洞问题(vue)

如果升级Vue版本有限制或者时间比较紧急&#xff0c;可以暂时用下面方式来&#xff0c;规避检测到目标站点存在javascript框架库vue漏洞。 在 vue.config.js 中配置: module.exports {configureWebpack: {optimization: {minimizer: [new (require(terser-webpack-plugin))({t…

【性能测试】-2- JMeter工具的使用

一、基础脚本搭建&#x1f3af; 核心目标&#xff1a;用 JMeter 搭性能测试 “骨架”&#xff08;测试计划、线程组、取样器、监听器&#xff09;&#x1f4cb; 测试计划&#xff1a;整个测试的 “容器”&#xff0c;所有测试组件都放这里&#x1f9f5; 线程组&#xff1a;模拟…

从零构建桌面写作软件的书籍管理系统:Electron + Vue 3 实战指南

&#x1f4da; 从零构建桌面写作软件的书籍管理系统&#xff1a;Electron Vue 3 实战指南 &#x1f4a1; 本文深入探讨了基于 Electron Vue 3 技术栈的桌面写作软件中书籍管理系统的设计与实现&#xff0c;涵盖了书籍的创建、编辑、删除等核心功能的完整技术方案&#xff0c;…

2025华数杯数学建模A题【 多孔膜光反射性能的优化与控制】原创论文讲解(含完整python代码)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2025华数杯数学建模A题【 多孔膜光反射性能的优化与控制】完整的成品论文。本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。A题论…

网络相关(AI回答)

网管交换机都支持带tag的以太帧吗DeepSeek-R1 回答完成深度思考完成 用时24秒&#xff0c;搜索全网20篇资料是的&#xff0c;所有网管交换机都支持处理和转发带Tag&#xff08;802.1Q VLAN标签&#xff09;的以太网帧&#xff0c;这是其核心功能之一。以下是关键要点&#xff1…

每日五个pyecharts可视化图表-bars(5)

探索pyecharts库中条形图的高级用法与定制技巧&#xff0c;打造精美数据可视化图表 在数据可视化中&#xff0c;条形图是最常用的图表类型之一。它能够清晰地展示不同类别的数据对比&#xff0c;帮助我们快速理解数据特征。本文将为您介绍pyecharts库中条形图的5种高级用法&…

分布式版本控制工具Git

一.开发中为什么需要Git因为在多人开发中Git可以管理代码&#xff0c;而且每个人都可以从库里面下载代码进行修改&#xff0c;每个人上传和修改Git都会有记录&#xff0c;如果出现大错误&#xff0c;还可以回退到正常版本。二.Git原理我们首先从代码库(Remote)下载代码到工作区…