DEX475

Third-Party Web Components (Beta)

课程介绍

同学们,今天我们来聊聊 Lightning Web Components 里一个挺有意思的新功能,就是用别人写好的、不是 LWC 的 Web 组件。不过要注意,这个功能目前还在 Beta 阶段,后面可能会有变化。 首先,想用这种第三方组件,必须先把你的 Salesforce 环境里那个叫 LWS 的服务打开——Lightning Web Security 得启用。而且有个小限制,Lightning 原生的按钮组件是不支持直接嵌第三方 Web 组件的,这点稍微记一下。 要把这些外部组件弄进来,有两种办法。第一种,你把它当成一个静态资源上传到 Salesforce,然后用一个特殊的工具叫 `platformResourceLoader` 去加载它。第二种呢,是直接把它做成一个 LWC 模块来添加。两种都可以,看你们项目怎么方便怎么来。 这些外来的组件,它们还是遵循标准的 Web Components 规矩来写的,比如要继承 `HTMLElement`,要有自己的生命周期方法,像 `connectedCallback` 这种,然后用 `customElements.define()` 注册一下,一般还会给它挂一个自己的影子根,也就是 shadow DOM。 那数据怎么传给它们呢?有三种路子:可以用普通的 HTML 属性,用组件的属性,或者用一个比较方便的指令 `lwc:spread`,把一串数据一次性传进去。如果你要往组件里面塞一大块内容,比如 HTML 片段,就用插槽,也就是 slot。 绑定事件的时候要注意,只能用 XML 格式的名字,不要写驼峰那种。样式这块也分情况:要是组件用了 shadow DOM,你就通过 CSS 自定义属性来传颜色、尺寸这些;要是它用的是 light DOM,那就可以用加了作用域的 class 来写样式。 对了,如果你的组件还要在手机上跑,那就还得遵守 Salesforce 给移动端准备的另外一套指导原则。 最后再提醒一下,这些东西都还在 Beta 测试,将来正式发布的时候很可能会调整,所以现在咱们先了解思路,别在生产环境大规模用。 好,这一页的核心差不多就这些。有什么问题随时问我。

课程章节

本课程共有 15 个章节

  • 1

    Third-Party Web Components — Overview & lwc:external

    第 232 页

    同学们,今天我们来看一个特别有用的技巧:怎么把不是 Salesforce 原生的第三方 Web 组件,优雅地塞进我们的 Lightning Web 组件里。 在 LWC 里,我们有时会碰到这样一个指令,叫 `lwc:external`。它的作用就是告诉框架:“嘿,下面这个元素不是我自家孩子,它是一个外部来的自定义元素,请按普通 Web 组件的规矩对待它,别用 LWC 那套去编译它。” 这样,外面的轮子就能在咱们的 Lightning 环境里跑起来了。 那具体怎么集成呢?主要有三种路子。 第一种,也是最标准的方法。把第三方库打包成静态资源上传,然后用 `platformResourceLoader` 去加载它。这就像你把一个现成的工具箱放到仓库里,需要的时候再拿出来用。注意啊,这里有限制:单个文件不能超过 5 MB,整个组织所有静态资源加起来不能超过 250 MB,所以别啥都往里塞。 第二种,稍微直接一点。你可以通过一个 `.js-meta.xml` 配置文件,把那个第三方的 JS 文件当成一个独立的 LWC 模块,直接放到你的项目结构里。这种情况下,JS 文件不能超过 1 MB。适合那些比较轻量的库。 第三种,最硬核的方式:你完全可以在 JavaScript 里自己用原生的 customElements API,手动去定义和注册一个自定义元素。这就像自己画图纸造零件,灵活性最高,但也要你更深的了解 Web 标准。 不管用哪种方法,有一个关键开关必须要打开,那就是 ,Lightning Web Security,。它必须启用,不然这些外部自定义元素可能没法正常工作。还有就是,收件箱(Inbox)这个地方是不支持自定义元素的,因为收件箱的架构本身不支持 Web Component 的基础设施,这点要心里有数。 另外提一句,这个第三方组件可以来源于任何流行框架,比如 React、Vue,也可以是纯粹的香草 JavaScript 写的 Web Component。基本上只要它最终是一个标准的自定义元素,就能用。 最后,作为一个负责任的 Salesforce 开发者,咱们在到处找第三方库之前,一定先花几分钟去 AppExchange 和官方的基本组件库里搜一搜。也许你想要的功能 Salesforce 早就给你准备好了,不用自己折腾集成,又稳定又省事。 好了,关于 `lwc:external` 引入外部组件的这三种方式,以及要注意的点,都讲清楚了。有什么问题随时问。

    查看详情
  • 2

    Example: Upload a Web Component as a Static Resource

    第 233 页

    今天我们来聊聊一个很有趣的例子——如何在Lightning Web Components里集成第三方的JavaScript库,来实现一个自动更新的时间显示组件。我们把这个例子叫做“时间元素”演示。 首先,我们有一个现成的JavaScript库,它提供了一些和时间相关的Web组件,比如显示相对时间、绝对时间等等。这个库本身是用普通JavaScript写的,不是Salesforce原生的。那我们怎么把它用在自己的LWC组件里呢?这就是静态资源集成的方法。 第一步,我们拿到这个库的JavaScript文件,把它上传到Salesforce的静态资源里,给它起个名字,比如“timeElements”。这样,Salesforce就会给它分配一个URL,我们在代码里可以通过`@salesforce/resourceUrl/timeElements`这个导入来获取这个URL。 接下来,在我们的LWC组件中,我们不能直接在模板里用这个库提供的自定义元素,得先把脚本加载进来。加载的时机很重要,我们在`renderedCallback`生命周期钩子里做这件事。`renderedCallback`会在组件渲染到DOM之后执行,确保有地方可以容纳这些自定义元素。 在加载脚本时,我们使用平台提供的`loadScript`方法,它是从`lightning/platformResourceLoader`里导入的。我们把之前获得的静态资源URL传进去。为了防止脚本被重复加载,我们通常设置一个标志位,比如一个私有属性`_scriptsLoaded`,如果已经加载过了就跳过,防止每次重新渲染都加载一遍。 这里我们用到了现代的`async/await`语法,并且用`try...catch`来包裹,这样如果加载失败,我们可以优雅地处理错误,比如在控制台输出或者显示一个错误消息。这就是清晰的错误处理模式。 当脚本成功加载后,这个库会在全局范围内注册它自己的自定义元素——这些元素名是库定义好的,比如`<local-time>`、`<relative-time>`之类。因为它们是通过外部脚本注册的,所以在我们的模板里直接使用这些标签时,需要用`lwc:external`这个指令来告诉LWC:“嘿,这个元素不是我定义的,是外部来的,不要把它编译掉。”这样,模板编译器就会原样保留这些标签。 一旦这些自定义元素被注册,它们就可以立即在模板里使用了。最棒的是,这个时间元素库本身已经实现了每分钟自动刷新显示的时间,我们完全不需要写额外的定时器或更新逻辑。组件会自动保持时间显示是最新的,比如显示“3分钟前”,它会随着时间推移变成“4分钟前”,完全自动。 总结一下整个过程:上传JS文件作为静态资源→导入URL→在`renderedCallback`里用`loadScript`加载并做防重处理→用`async/await`加`try/catch`确保健壮性→在模板里使用带`lwc:external`的自定义标签→享受自动更新的时间显示。 这看起来复杂,但一旦你掌握了这个模式,就可以把任何类似的Web组件库集成到LWC里,大大扩展你组件的功能。大家可以在动手实践中慢慢熟悉,其实并不难。

    查看详情
  • 3

    Example: Add a Web Component as an LWC Module

    第 234 页

    好的同学们,今天我们来聊聊如何在 Lightning Web Components 里整合第三方的 Web 组件,也就是 LWC 模块方法。这个概念不难,我会慢慢拆开来讲。 想象一下,你手上有一个现成的、用标准 Web 技术写的组件,比如一个漂亮的图表或者一个日期选择器。你想把它直接放进你的 Salesforce 项目里用,而且希望它能和 LWC 的无障碍、响应式特性无缝配合。那怎么做到呢?答案就是用 LWC 模块方法。 这个模式其实包含两个部分,就像一枚硬币的两面。第一面是一个,自定义元素类,,它不是继承自 LightningElement,而是直接继承浏览器原生的 HTMLElement。这个类专门负责这个第三方组件内部的 DOM 结构创建。它会用最基础的 Web API,比如 `document.createElement` 来造元素,`setProperty` 来设属性,`appendChild` 来挂载节点,还会用 `attachShadow` 开启一个影子根。我们熟悉的那个 `shadowRoot` 就是这时候生成的,它能把 CSS 样式封装起来,确保组件的样式不会跑到外面去,外部的样式也不会干扰里面。 第二部分就是咱们熟悉的 ,LWC 组件类,了,它必须继承 `LightningElement`。这个类扮演着“桥梁”的角色,一边连接着 Salesforce 的资源,比如静态资源、标签、数据服务,另一边把那些资源变成响应式的属性,暴露给前面那个自定义元素。比方说,你在 Salesforce 里上传了一个图片静态资源,然后在这个 LWC 类里通过 `@wire` 或导入的方式拿到它,再把它当作一个属性传给自定义元素,这样第三方组件就能展示 Salesforce 里的图片了。 这里有个很关键的小指令,叫 `lwc:external`。当你在 LWC 的模板里使用那个自定义元素的标签时,需要加上这个指令。它的作用就是告诉 LWC 引擎:“嘿,这个标签不是用 LightningElement 写的,是我自己注册的外部元素,你别把它当成普通的 LWC 去管理。” 这样引擎就会跳过一些针对 LightningElement 的检查,让自定义元素自由发挥。 最后还要记得,那个自定义元素类写好后,要用原生的 `customElements.define()` 方法全局注册一下,这样它才能在模板里被识别和使用。 所以总结一下,整个流程就是:先写好一个标准的 Web Component 作为“内核”,再用一个 LWC 包裹层把它接上 Salesforce 的数据和资源,通过 `lwc:external` 声明一下,就能光明正大地在你的 Lightning 页面里跑起来了。是不是就像给一个纯原生组件穿上 Salesforce 的外衣?这样既保留了原生 Web 组件的灵活与强大,又享受到了 Salesforce 平台的全部能力。 好,这就是 LWC 模块方法的精髓,相信大家现在已经有一个清晰的轮廓了。有什么疑问吗?

    查看详情
  • 4

    Third-Party Web Components — Known Issues & Guidelines

    第 235 页

    同学们,今天我们来聊聊 Lightning Web Components 开发者指南中一个非常实用的部分——测试版功能。在使用这些测试版功能的时候,有一些已知问题和必须遵守的指南,我们一条一条来看。 首先,通过加载脚本不支持 ECMAScript 模块,也就是我们常说的 ES 模块。所以你只能使用预先打包好的 IIFE 或者 UMD 格式的脚本。简单说,就是不要直接加载那种用 import 和 export 的现代 JS 文件,得用已经打包成传统格式的。 其次,由于 LWC 本身不支持 npm 导入,凡是有依赖关系的基于 npm 的组件,就没法直接用了。如果你想用第三方库,得先把它转换成单个文件,并且不能带 npm 的模块依赖。 接着看,在影子的多姆里,基于 ID 的元素引用会失败。因为组件默认是封闭的,无法访问全局的 document 对象。所以别想着用 document.getElementById 去获取影子多姆里的元素,得用组件内部的模板引用。 另外,Experience Builder 站点不支持 LWS 的第三方组件。就是说,如果你在 Experience Cloud 里搭建网站,暂时不能用轻量级服务(LWS)的第三方组件。 还有,自定义内置元素,也就是用 extends 继承原生 HTML 元素的写法,是不支持的。只能创建独立的自定义元素。 关于数据传递,默认情况下,属性值只会作为 attribute 存在,前提是这个属性已经被定义过。插槽(slot)功能是有效的,但合成阴影插槽不能用。只支持根模板上的标签,其他标签如果需要,得用 addEventHandler 来手动添加事件处理。 事件名称必须严格按照 RST 规范来命名,不能随意取。如果你想监听属性变化,要用 deliveredCallback 或者 attributeChangedCallback 方法,来获取那些需要反应的属性。 另外,不支持动态创建组件,也就是说,不能像以前那样在运行时用代码 new 出一个组件实例。还有,注册时机对于接收动态值非常关键,如果注册晚了,可能就拿不到初始的动态值了。 好了,这些就是关于测试版功能的主要注意事项。理解了这些,你就能更好地避开坑,把 LWC 用得顺顺利利。我们下节课见!

    查看详情
  • 5

    Work with Custom Elements — Define & Register

    第 236 页

    好,同学们,咱们今天来聊聊 LWC 里的一个很特别的话题——自定义元素。听起来有点儿技术,但别担心,我会用最简单的方式让你听明白。 首先你要知道,LWC 的自定义元素,它是完全遵循浏览器原生的 Web 组件规范的。这就意味着你写的这个组件,它就是一个标准的 HTMLElement 子类。注意,必须继承 HTMLElement,而且要用带连字符的唯一名称去注册,就像 my-component 这样,不能用单个单词,这是浏览器要求的。 那它的生命周期呢,其实跟咱们熟悉的 LWC 组件很相似,只是术语更贴近原生的 Web 组件概念。比如,构造函数里我们做初始化、附加影子根;元素被插入到 DOM 树的时候,会触发 connectedCallback;被移除的时候触发 disconnectedCallback。还有一个静态属性叫 observedAttributes,它是一个数组,用来告诉浏览器你要监听哪些属性的变化。当这些属性变化时,就会调用 attributeChangedCallback。还有一个不太常用到的回调叫 adoptedCallback,就是当元素从一个文档移动到另一个文档时触发的,比如调用 adoptNode 的时候。 那么怎么在 LWC 里使用这种自定义元素呢?有两种方式。一种很简单,就在你的 LWC 的 JavaScript 文件里,直接在 export default class 定义之前,写自定义元素的类定义,然后顺便注册它。另一种更模块化一点,你可以把它单独放在组件捆绑包里的一个单独文件里,然后导入到主 JS 文件中使用。这样代码结构更清晰。 有一点要特别注意:自定义元素里的模板,也就是 template 标签,是可选的。如果你不用模板,那就要完全用程序来创建元素内部的 DOM 结构。而且切记,LWC 的 HTML 模板里面是不能放嵌套 template 标签的,这点跟纯 Web 组件可以不同。所以如果你要在 LWC 里使用自定义元素,模板方式就得放下,按照原生方式手动来。 好,关于自定义元素的核心点就这么多。你只要记住,它是标准 Web 组件的那套玩法,生命周期和注册方式都遵循规范,在 LWC 中可以直接内联也可以分开写,但要避免在 HTML 模板里直接用 template 标签。是不是挺简单的?下节课我们拿个例子练练手,这样你就更有感觉了。

    查看详情
  • 6

    Attach a Shadow Root to a Custom Element

    第 237 页

    我们来看一个在做自定义元素时非常重要的决定,就是影子根的模式选择。 你得在两种模式里挑一个:开放模式,或者关闭模式。开发模式是咱们最常见的选择。为什么选它?因为开放模式允许外部JavaScript通过元素的shadowRoot属性直接访问影子树。这就好比你的组件有个透明的外壳,外面的人可以往里看,可以检查和测试里面的结构。这样一来,我们在写测试代码、调试工具,甚至是浏览器的开发者工具里,都可以很方便地查看组件的内部。在开放模式下,你可以直接在影子根上使用像appendChild、adoptedStyleSheets这样的标准Web API,操作起来很顺手。 而关闭模式呢,就不一样了。它会直接让element.shadowRoot返回空值,阻止外部代码访问。不过,这里有个重要的点要理解:关闭模式不是一种安全功能。它更像是一个声明:告诉别人,“这些内部细节是私有的,别依赖它们来写代码。” 比如,你可以在自定义元素的类里,用一个私有属性,像this._shadow,来保存对影子根的引用,这样组件内部照样可以操作自己的影子DOM,从生命周期回调里查询和更新。但外部就访问不到了。 那到底该怎么选呢?就一条简单的规则:看你想不想让外部代码能够检查组件内部。如果你想支持测试和调试,就用开放模式。如果你确实想表明这个组件的内部实现以后随时可能变化,不希望别人依赖它,那就可以用关闭模式。但大多数时候,我们都会选择开放模式,因为它更灵活、更方便。

    查看详情
  • 7

    Custom Elements — Import & Use in LWC

    第 238 页

    同学们,咱们今天聊一下在 LWC 里定义自定义元素的两种模式。这就像你写 HTML 时,有时需要自己造一个特殊标签,比如一个带样式的星星符号,或者一个自定义的进度条。LWC 给你两种方法来实现它。 第一种,叫,内联模式,。意思就是直接在 LWC 组件的这个 JavaScript 文件里,在类定义之前,就用标准 Web 标准的 `customElements.define` 方法把这个元素给注册上。你可以理解成,在这个文件开头顺手就把小工具定义好了,写起来最快。比如你只需要一个很简单的彩色小圆点,只在这一个组件里用一下,那用内联模式就刚刚好,不绕远路。 第二种,叫,单独文件模式,。如果你觉得这个小工具以后还会在其他地方用到,或者它逻辑比较复杂,那就把它拆到自己单独的一个 .js 文件里,就放在组件包里。然后在主组件里用一句 `import './myCustomElement'` 来引入它。这句 import 其实不需要赋值给变量,它就是个副作用导入——一执行,那个文件里的自定义元素就自动在全局注册好了。这样,你的元素定义干净独立,未来别的组件想用,都可以直接这样导入,复用性更强。 两种模式下,你在模板里使用这个自定义标签的时候,都要在标签上加上 `lwc:external` 这个指令,这样 LWC 才会把它当成外部的标准自定义元素来处理,而不是内部的 LWC 组件。 还有一点开发习惯要记住:如果你想在元素创建或者挂载的时候处理一些属性、子元素啥的,,别用构造函数,。推荐你用 `connectedCallback` 或者 `renderedCallback` 来安全操作。如果想监听到某个属性值变化然后做出反应,就用 `attributeChangedCallback` 这个标准回调。这样代码更稳健,不会和 LWC 的渲染周期打架。 简单来说,小工具就地解决,用内联;想长期重复使用的,拆到单独文件,副作用导入。模板里别忘加 `lwc:external`,生命周期用对钩子。好了,这个点讲明白了,下面咱们看看实际例子。

    查看详情
  • 8

    Example: Counter Button with Lifecycle Callbacks

    第 239 页

    同学们,我们来看一下这个示例,这是一个计数器按钮,它完美地演示了自定义元素的生命周期模式。我们一点点把它拆开,让你彻底明白它是怎么工作的。 首先,处理程序这里,我们用箭头函数来定义,比如点击事件的处理函数。为什么要用箭头函数?因为它可以自动保留正确的 `this` 上下文,这样你在函数里面用 `this` 的时候,指向的就是你的自定义元素实例,不会搞乱。 然后看构造函数。在构造函数里,我们设置初始的 HTML,把计数设为 0,显示在按钮上。这是自定义元素被创建时最先执行的。 接下来是 `connectedCallback`。这个生命周期钩子会在元素被插入到 DOM 的时候触发。这时候元素已经在页面里了,所以是添加事件监听器的最佳时机。我们在这里给按钮加上点击事件,这样用户才能交互。 相对应的,`disconnectedCallback` 会在元素从 DOM 中移除时调用。我们一定要在这个回调里移除之前添加的事件监听器,避免内存泄漏。这对于那些可能被反复添加和删除的元素特别关键,不然你的页面会越来越慢。 当用户点击按钮时,点击处理程序会把计数加一,然后直接更新按钮的 `innerHTML`,显示出新的数字。整个过程简洁明了。 接着,我们把这个自定义元素注册到浏览器,给它一个标签名。然后在 Lightning Web Components 里使用时,你需要在模板里用 `lwc:external` 指令来引用它,因为这个元素不是标准的 LWC 组件,而是原生的自定义元素。 最后,渲染出来的 DOM 结构你注意到了吗?宿主组件会把它包裹在一个封闭的阴影根里。也就是说,自定义元素对外是封装的,样式和 DOM 都隔离,这就是 Web Component 的强大之处。 总结一下,通过这个计数器,我们看到了自定义元素从创建、连接到 DOM、更新、再到断开连接的完整生命周期,以及如何在 LWC 中安全地使用它们。记得抓住两点:用箭头函数保证 `this` 正确,在 `connectedCallback` 和 `disconnectedCallback` 里管理好事件监听器。这样你就能驾驭自定义元素啦!

    查看详情
  • 9

    Example: Counter with Attribute Change Callback

    第 240 页

    同学们,今天我们来学一个更高级的计数器写法,叫作,属性观察模式,。别害怕,其实很简单。 还记得我们之前做的计数器吗?这次我们让它变得更灵活:不管是在组件内部改,还是从外部改计数,页面都能自动更新。 首先,我们把,计数,做成一个 `getter/setter` 对。 - 当你在代码里读 `this.count` 时,它实际上读取的是 HTML 属性上的值。 - 当你写 `this.count = 5` 时,它不仅更新了变量,还会把组件对应的 HTML 属性 `count` 也给更新一下。 这样,,属性, 和 HTML 上的 ,特性, 就永远保持同步了。 然后,我们通过 `observedAttributes` 这个静态属性,告诉浏览器:“嘿,帮我看好 `count` 这个属性,一旦它变了,叫我来处理。” 注意,Slide 上可能有个笔误,写成了 “DelivervedLedger”,实际就是 `observedAttributes`。 一旦计数属性变化,浏览器就会自动调用 `attributeChangedCallback` 回调函数。在这里面,我们要做两件事: 1. 重新渲染按钮的 HTML,好让界面上显示的数字更新。 2. 重新绑定事件监听器,这样按钮才能正常工作。 因为渲染按钮这段代码在 `connectedCallback`(组件连上 DOM 时)也要用,我们把它抽成一个 `renderButton` 方法,避免重复。这样代码干净又好维护。 最后,增量处理函数(比如每点一次加一那个方法)里,我用 `.bind(this)` 来保持函数的上下文。有些同学习惯用箭头函数,这里 `.bind(this)` 也是同样效果,就是让方法里的 `this` 一直指向组件实例,不会跑丢。 什么时候用这种模式呢? 就是当你的组件状态需要,从外面,来设置的时候,比如别人通过 `setProperty` 或者直接赋值来改 `count`,而你的 UI 又必须立即跟着变。这个模式就是专门解决这种场景的。 简单总结: - 用 `getter/setter` 同步属性和特性 - 用 `observedAttributes` 盯住变化 - 在 `attributeChangedCallback` 里刷新界面 - 把重复渲染逻辑抽成方法 - 用 `.bind(this)` 保住上下文 这样,你的组件就健壮又好用了。下节课我们配上例子看一眼代码,就更清楚啦。

    查看详情
  • 10

    Example: Random Square with Conditional Display

    第 241 页

    同学,我们来看一个在Lightning Web Components里很重要的设计模式:如何有条件地显示一个自定义元素。 很多时候,你可能会想,“我直接用 JavaScript 操作 DOM 行不行?比如 appendChild、removeChild?” 但 Salesforce 推荐的方式更声明式,也更安全,就是用 `lwc:if` 这个指令。为什么?因为它能自动帮你触发自定义元素的生命周期回调,也就是 `connectedCallback` 和 `disconnectedCallback`。这一点特别关键,因为当你用命令式操作 DOM 时,这些回调可能不会按预期触发,导致内存泄漏或者状态不同步。 我们来看这个例子。有一个自定义元素叫 `custom-square`,它定义在 `customSquare.js` 里。这个元素有几个特性:它有颜色和大小的属性,还有一个 `updateStyle` 方法来根据属性动态注入 CSS。并且它会在控制台记录生命周期事件,这样你就能清清楚楚看到组件什么时候被创建、什么时候被移除。 同时,我们的父组件(也就是 LWC 组件)负责管理所有状态。它维护着 `showSquare` 变量来控制自定义元素的显示和隐藏;还有一个 `buttonDisabled` 状态来决定按钮是否可用;以及一些方法来添加、更新或删除“收件箱”里的项目。在这个模板里,我们用 `lightning-button` 来切换显示,并且把从按钮选出的颜色和大小值当作反应属性传给 `custom-square`。 所以整体流程就是:当你点击按钮,`showSquare` 状态改变,`lwc:if` 条件重新计算,如果为 true,`custom-square` 就被渲染,其 `connectedCallback` 自动执行,你的日志就会输出;如果为 false,元素被移除,`disconnectedCallback` 执行。这样你就不需要自己操作 DOM,数据流清晰,生命周期可预测,代码也更简洁。 记住这个模式:用 `lwc:if` 来控制自定义元素的可见性,而不是直接 append 或 remove。这既符合框架的最佳实践,也让你的组件更容易维护。

    查看详情
  • 11

    Pass Data to a Custom Element — Attributes & Properties

    第 242 页

    同学,咱们今天来讲一个关于Lightning Web Components里数据传递的细节,这个点虽然有点绕,但是理解了以后能避免很多坑。 你往自定义组件里传数据的时候,LWC默认是按照HTML属性的方式来传的。什么是HTML属性?就是在标签上写的那一串东西,它本质上都是字符串。所以如果你直接传过去一个布尔值true,LWC会把它转成字符串“true”传进去。 如果你的组件里面恰好有同名的属性设置器(setter),LWC就会聪明地用那个setter来接收数据,这就变成真正的JavaScript属性了。那这三者有什么区别呢?关键就在于后续的变化。 如果你用的是HTML属性,当外界数据发生变化、重新渲染时,LWC默认不会自动再帮你调那个属性了。要是你想响应这种变化,就得自己实现两个生命周期钩子:一个是`attributeChangedCallback`,一个是`renderedCallback`。否则,属性的变化会被悄悄地忽略掉,你的组件外观不会更新,这就是最容易出bug的地方。 那怎么省事儿呢?用属性的getter和setter模式。你只需要在组件类里定义好getter和setter,LWC在传值的时候就会自动检测到,然后调用setter,并且帮你处理好类型的序列化和反序列化。比如你传布尔值,setter收到的是真正的布尔值,而不是字符串“true”,省去了自己转换的麻烦。 最后,如果自定义组件要接收一堆属性值,LWC提供了一个很方便的指令叫`lwc:spread`,你可以直接把一个对象展开传给组件,它会自动把对象的属性对应到组件里的setter上。这种方式特别适合属性很多的时候,代码简洁又不容易出错。 简单总结一下:传数据优先用属性setter/getter,这样类型自动转换,变化也能自动响应。如果想直接控制变化时机,就用HTML属性加回调函数。批量传值就用`lwc:spread`。记住了吗?下次写代码的时候,多留意这些细微差别,你的组件就会变得更健壮。

    查看详情
  • 12

    Pass Data to Child & Slots in Custom Elements

    第 243 页

    大家好,今天我们来聊聊在Lightning Web Components中,怎么把数据和内容传给子组件,这跟咱们熟悉的标准LWC模式其实很像。 先说数据传递。如果你想向子组件发送一堆属性,父组件里可以用一个特殊的指令叫lwc:spread,它相当于把一组属性“展开”传递给子组件。子组件那边呢,只要在对应的属性上加上@api装饰器,就能接收到这些值了。非常简单,就像把一叠卡片一下子递给对方,对方伸手接住就行。 接着是内容传递,这里用到的就是插槽——slot。在自定义元素内部,你可以定义插槽的位置,好比在模板里挖好一个空位。父组件在调用这个子组件时,只要把内容写在它的标签之间,这段内容就会自动填进那个空位。这和标准LWC插槽的用法是一模一样的:自定义元素在它的影子DOM里写好slot元素,使用方只要在标签中间放内容就可以。 如果涉及到命名插槽,原理就是匹配名字。子元素上给一个slot属性指定名称,插槽元素那边用name属性来对应。名字一样的,就会配对成功。要是内容上没有slot属性,那它就会掉进默认插槽,也就是没有名字的那个。 最后提醒一点,一个重要的限制:如果你在项目中用的是第三方组件,要注意合成阴影插槽是不被支持的。也就是说,slot只有在浏览器原生支持的Shadow DOM环境下才能完美工作。好消息是,原生Shadow DOM还会保留顶级自定义元素里面的插槽内容,确保结构清晰。 总结一下,就是把属性用lwc:spread传过去,内容用slot机制填进去,命名插槽靠名称匹配,默认插槽兜底。但务必确保运行环境是原生Shadow DOM,这样才能保证插槽行为不出错。 今天的知识点就是这样,咱们下次继续。

    查看详情
  • 13

    Events in Third-Party Web Components & Considerations

    第 244 页

    同学们,我们来看看在Lightning Web Components里用第三方Web组件时,处理事件的一个小坑。很多时候,我们习惯在模板里直接写`oneventname`这样的声明式绑定,比如`onclick`。但是,这种写法有个关键限制:它只对完全小写的事件名称有效。如果你的第三方组件发出的事件名是驼峰式、帕斯卡式或者带连字符的,那模板里的声明式绑定就识别不了了。 那怎么办呢?你必须在组件的构造函数里,用代码手动调用`addEventListener`来监听这些事件。记住,你自己在第三方组件里触发事件,也最好用标准的`CustomEvent`构造函数,跟LWC里一样,这样兼容性好。 还有一个要注意的点:如果浏览器不认识你的自定义元素,它会把它们当成`HTMLUnknownElement`来处理,说白了就是一个通用容器,像`span`或`div`一样,没有任何特殊行为。只有当自定义元素注册之后,它的“升级”过程才开始。这个升级的时间点很重要:在升级之前,LWC会把我们传过去的属性设置成HTML属性;一旦升级完成,如果组件有对应的属性定义,这些属性才会真正生效,变成JavaScript属性。所以,如果你是从静态资源同步加载并注册组件,就会有一个短暂的时间窗口,属性先被当作字符串属性设上去,然后升级后可能被覆盖成正确的值。要做好心理准备,安排好加载顺序。 简单来说,遇到第三方Web组件的事件,名称不是全小写,就别偷懒用模板绑定了,老老实实在代码里`addEventListener`。另外,注意自定义元素的注册时机,避免属性设置的意外情况。这样,你就能平稳地集成第三方组件了。

    查看详情
  • 14

    Append Styles to a Custom Element — Shadow DOM

    第 245 页

    好了,同学们,我们来看一下关于第三方Web组件样式的一个重要概念。这取决于它们底层用的是哪种DOM模型——主要是影子DOM。 影子DOM就像给组件的内部加了一层保护罩,样式是完全封装的。也就是说,你没法直接从外边强行修改它里面的按钮、字体这些细节,同时组件内部的样式也不会跑出来干扰你页面的其他部分。这保证了组件的独立性,但也带来了一个问题:怎么安全地定制它的外观呢? 答案就是CSS自定义属性,也就是我们常说的`--变量`。这种变量非常厉害,能穿透影子DOM的边界。所以啊,如果组件的作者在内部用了`var(--某个属性, 默认值)`这样的写法,那你就可以在它的宿主元素上,或者任意一个祖先元素上,给这个自定义属性赋一个新值,就能覆盖掉默认样式了。这是一种标准、优雅的定制方式,你不需要去动组件内部结构。 那宿主元素本身呢?也就是你看到的那个自定义标签,比如 `<my-button>`,你想设置它的外边距、显示模式,怎么办?这很简单,直接在你的CSS文件里用元素选择器,就是直接写标签名给它加样式,这影响的是外部容器,当然没问题。 最后提醒大家一句,任何时候用第三方组件,一定要先去看它的文档或源码,搞清楚它暴露了哪些自定义属性,或者有没有开放`::part`伪元素。千万别去硬猜它的内部class结构然后强行覆盖,那样不仅脆弱,而且随时可能失效。记住,尊重封装,用对方法,样式定制才能稳。好,就讲到这里。

    查看详情
  • 15

    Append Styles — Light DOM & Mobile-Ready Components

    第 246 页

    好,同学们,咱们今天来看看第三方组件的样式,特别是轻量级DOM和阴影DOM的区别。你会发现,处理轻量级DOM的样式,比阴影DOM简单得多。 为什么呢?因为没有阴影边界来阻止样式继承。在轻量级DOM里,标准的CSS类直接就能生效,就像咱们平时写网页一样。你可以直接用普通的.css文件,样式自然就会全局应用到组件内部。如果你想把样式限制在这个组件里,不影响到外面,也可以用加了.scoped.css后缀的样式文件,这样就是组件作用域的样式,只会对当前组件内的元素起作用。 接下来,我们快速总结一下,在不同场景下,组件样式的处理方式。 第一种场景,开放的 shadow DOM。这种情况下,你可以用CSS自定义属性,也就是变量,从外部穿透进去改变组件内部样式;还能用:host选择器调整组件本身的宿主元素。如果组件内部暴露了一些用::part定义的部件,你也能从外部定制它们。 第二种场景,封闭的阴影 DOM。这里就限制更多了,因为没有暴露内部结构,你只能用CSS自定义属性和:host选择器,无法直接改动组件内部的元素。 第三种就是咱们刚说的轻量级DOM,也就是light DOM。最灵活,你直接用标准CSS,配合普通类名和作用域样式表,随心所欲地写样式。 最后,再提一句移动就绪的组件。LWC天生就支持桌面和移动设备,但移动设备有些不同的限制和功能,不仅是屏幕大小的问题。如果你要深入移动开发,可以去看专门的《移动和离线开发人员指南》,里面详细讲了怎么用闪电移动功能模块来构建移动应用。 好了,关于轻量级DOM样式和移动适配的概述就到这儿,大家有问题吗?

    查看详情