Vue3 构建 Web Components使用详解

目录
  • 引言
  • 构建 Web Components
    • 属性
    • 事件
    • 插槽
    • 子组件样式问题
    • 方法
  • 总结

引言

有时候想写一个无关框架组件,又不想用原生或者 Jquery 那套去写,而且还要避免样式冲突,用 Web Components 去做刚觉就挺合适的。但是现在 Web Components 使用起来还是不够灵活,很多地方还是不太方便的,如果能和 MVVM 搭配使用就好了。

早在之前 Angular 就支持将组件构建成 Web Components,Vue3 3.2+ 开始终于支持将组建构建成 Web Components 了。正好最近想重构下评论插件,于是上手试了试。

构建 Web Components

vue 提供了一个 defineCustomElement 方法,用来将 vue 组件转换成一个扩展至HTMLElement的自定义函数构造函数,使用方式和 defineComponent 参数api基本保持一致。

import { defineCustomElement } from 'vue'
const MyVueElement = defineCustomElement({
  // 在此提供正常的 Vue 组件选项
  props: {},
  emits: {},
  template: `...`,
  // defineCustomElement 独有特性: CSS 会被注入到隐式根 (shadow root) 中
  styles: [`/* inlined css */`]
})
// 注册 Web Components
customElements.define('my-vue-element', MyVueElement)

如果需要使用单文件,需要 @vitejs/plugin-vue@^1.4.0 或 vue-loader@^16.5.0 或更高版本工具。如果只是部分文件需要使用,可以将后缀改为 .ce.vue 。

若果需要将所有文件都构建 Web Components 可以将 @vitejs/plugin-vue@^1.4.0 或 vue-loader@^16.5.0 的 customElement 配置项开启。这样不需要再使用 .ce.vue 后缀名了。

属性

vue 会把所有的的 props 自定义元素的对象的 property 上,也会将自定义元素标签上的 attribute 做一个映射。

<com-demo type="a"></com-demo>
props:{
  type:String
}

因为 HTML 的 attribute 的只能是字符串,除了基础类型(Boolean、Number) Vue 在映射时会帮忙做类型转换,其他复杂类型则需要设置到 DOM property 上。

事件

在自定义元素中,通过 this.$emit 或在 setup 中的 emit 发出的事件会被调度为原生 CustomEvents。附加的事件参数 (payload) 会作为数组暴露在 CustomEvent 对象的 details property 上。

插槽

编写组件时,可以想 vue 一样,但是使用时只能原生的插槽语法,所以也不在支持作用域插槽。

子组件样式问题

使用子组件嵌套的时,有个坑的地方就是默认不会将子组件里的样式抽离出来。

父组件

<template>
    <div class="title">{{ title }}</div>
    <Childer />
</template>
<script>
import Childer from "./childer.vue"
export default {
    components: { Childer },
    data() {
        return {
            title: "父组件"
        }
    },
}
</script>
<style lang="less" scoped>
.title {
    padding: 10px;
    background-color: #eee;
    font-weight: bold;
}
</style>

子组件

<template>
    <div class="childer">{{ title }}</div>
</template>
<script>
export default {
    data() {
        return {
            title: "子组件"
        }
    },
}
</script>
<style lang="less" scoped>
.childer {
    padding: 10px;
    background-color: #222;
    color: #fff;
    font-weight: bold;
}
</style>

可以看到子组件的样式没有插入进去,但是样式隔离的标识是有生成的 data-v-5e87e937。不知道vue官方后续会不会修复这个bug

查看组件是可以看到,子组件的样式是有被抽离出来的,这样就只需要自己注入进去了。

将子组件样式抽离插入到父组件里,参考这个的实现

import ComDemo from '~/demo/index.vue'
const deepStylesOf = ({ styles = [], components = {} }) => {
    const unique = array => [...new Set(array)];
    return unique([...styles, ...Object.values(components).flatMap(deepStylesOf)]);
}
// 将子组件样式插入到父组件里
ComDemo.styles = deepStylesOf(ComDemo)
!customElements.get('com-demo') && customElements.define('com-demo', defineCustomElement(ComDemo))

完美解决子组件样式问题

方法

defineCustomElement 构建的组件默认是不会将方法挂到 customElement 上的,看 Vue 源码中,只有 _def(构造函数),_instance(组件实例))。

如果想调用组件内的方法,dom._instance.proxy.fun(),感觉实在不太优雅。

我们当然希望我们组件暴露的方法能像普通dom那样直接 dom.fun() 去掉用,我们对 defineCustomElement 稍作扩展。

import { VueElement, defineComponent } from 'vue'
const defineCustomElement = (options, hydate) => {
    const Comp = defineComponent(options);
    class VueCustomElement extends VueElement {
        constructor(initialProps) {
            super(Comp, initialProps, hydate);
            if (Comp.methods) {
                Object.keys(Comp.methods).forEach(key => {
                    // 将所有非下划线开头方法 绑定到 元素上
                    if(!/^_/.test(key)){
                        this[key] = function (...res) {
                            if (this._instance) {
                                // 将方法thi改为 组件实例的proxy
                                return Comp.methods[key].call(this._instance.proxy, ...res)
                            } else {
                                throw new Error('未找到组件实例')
                            }
                        }
                    }
                })
            }
        }
    }
    VueCustomElement.def = Comp;
    return VueCustomElement;
}

总结

总体来说坑还是有不少的,如果仅仅需要构建一些比较简单跨框架插件,使用这种方式来构建 Web Components 也是一种不错的方案。

以上就是Vue3 构建 Web Components使用详解的详细内容,更多关于Vue3 构建 Web Components的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue3中使用pnpm搭建monorepo开发环境

    目录 前言 Pnpm 和 Monorepo 搭建开发环境 创建项目 配置 monorepo 安装依赖 初始化Typescript 准备两个模块 shared reactivity 编写构建脚本 完成第一次调试 小结 前言 Vue3 源码阅读系列,计划从环境搭建开始,将 Vue3 的响应式模块,运行时模块和编译器模块,以及状态库 Pinia.路由库 Vue-Router的核心原理做一个梳理.这大概是一个漫长的过程.祝自己不要烂尾,祝大家有所收获. Pnpm 和 Monorepo Pnpm 是新一代

  • 详解vue3中如何使用youtube-player

    目录 正文 开始使用 做成组件youtubePlayer 使用方式 注意事项 常用参数 常用API 正文 youtube-player 是 YouTube IFrame Player API (YIPA) 的封装.可以在自己网站上播放YouTube视频. 开始使用 使用 npm 下载 npm i youtube-player 做成组件youtubePlayer <script setup> import { ref, watch, onMounted, onBeforeUnmount } fr

  • 详解vue3中如何使用shaka-player

    目录 正文 开始使用 做成组件shakaPlayer 使用方式 注意事项 正文 Shaka Player 是谷歌公司对外开源的一款 JavaScript 类库,详细请看谷歌官方API文档. 开始使用 我们可以使用 npm 下载 npm i shaka-player 做成组件shakaPlayer <script setup> import { ref, watch, onMounted, onBeforeUnmount } from "vue"; import shaka

  • vue3使用自定义指令实现el dialog拖拽功能示例详解

    目录 实现el-dialog的拖拽功能 通过自定义指令实现拖拽功能 实现拖拽功能 使用方式 实现el-dialog的拖拽功能 这里指的是 element-plus 的el-dialog组件,一开始该组件并没有实现拖拽的功能,当然现在可以通过设置属性的方式实现拖拽. 自带的拖拽功能非常严谨,拖拽时判断是否拖拽出窗口,如果出去了会阻止拖拽. 如果自带的拖拽功能可以满足需求的话,可以跳过本文. 通过自定义指令实现拖拽功能 因为要自己操作dom(设置事件),所以感觉还是使用自定义指令更直接一些,而且对原

  • vue3 Vite 进阶rollup命令行使用详解

    目录 rollup介绍 以命令行方式打包 Tree Shaking Rollup 的命令行使用 命令行 format 格式 rollup.config.js 设置/获取环境变量 插件 plugins rollup介绍 开源类库优先选择 以 ESM 标准为目标的构建工具 Tree Shaking 以命令行方式打包 安装 rollup npm install -g rollup 创建 index.js 文件 import path from "path"; console.log(&quo

  • Vue3 源码解读之 Teleport 组件使用示例

    目录 Teleport 组件解决的问题 Teleport 组件的基本结构 Teleport 组件 process 函数 Teleport 组件的挂载 Teleport 组件的更新 moveTeleport 移动Teleport 组件 hydrateTeleport 服务端渲染 Teleport 组件 总结 Teleport 组件解决的问题 版本:3.2.31 如果要实现一个 “蒙层” 的功能,并且该 “蒙层” 可以遮挡页面上的所有元素,通常情况下我们会选择直接在 标签下渲染 “蒙层” 内容.如果

  • vue3 name 属性的使用技巧详解

    目录 引言 使用步骤 引言 如果你在 vue3 开发中使用了 <script setup> 语法的话,对于组件的 name 属性,需要做一番额外的处理. 对于 vue@3.2.34 及以上版本,在使用 <script setup> 的单文件组件时,vue 会根据组件文件名,自动推导出 name 属性.也就是名为 MyComponent.vue 或 my-component.vue 的文件, name 属性为 MyComponent,而当你在组件内显示定义 name 属性时,会覆盖推

  • Vue3 构建 Web Components使用详解

    目录 引言 构建 Web Components 属性 事件 插槽 子组件样式问题 方法 总结 引言 有时候想写一个无关框架组件,又不想用原生或者 Jquery 那套去写,而且还要避免样式冲突,用 Web Components 去做刚觉就挺合适的.但是现在 Web Components 使用起来还是不够灵活,很多地方还是不太方便的,如果能和 MVVM 搭配使用就好了. 早在之前 Angular 就支持将组件构建成 Web Components,Vue3 3.2+ 开始终于支持将组建构建成 Web

  • Java 内置Http Server构建web应用案例详解

    一.概述 使用Java技术构建Web应用时, 我们通常离不开tomcat和jetty之类的servlet容器,这些Web服务器功能强大,性能强劲,深受欢迎,是运行大型Web应用的必备神器. 虽然Java的设计初衷就是用来开发大型应用的,然而有时候我们开发的程序只是简单的小型应用,对于功能的需求和性能的要求并不高, 可能仅仅就几百行甚至几十行代码,这个时候使用tomcat之类的Web服务器去运行就显得有点大材小用了. 比如说只是将数据库中的数据读出来转换成JSON,以Web服务的形式吐给调用方这样

  • 何时/使用 Vue3 render 函数的教程详解

    什么是 DOM? 如果我们把这个 HTML 加载到浏览器中,浏览器创建这些节点,用来显示网页.所以这个HTML映射到一系列DOM节点,然后我们可以使用JavaScript进行操作.例如: let item = document.getElementByTagName('h1')[0] item.textContent = "New Heading" VDOM 网页可以有很多DOM节点,这意味着DOM树可以有数千个节点.这就是为什么我们有像Vue这样的框架,帮我们干这些重活儿,并进行大量

  • Vue3插槽Slot实现原理详解

    目录 Vue官方对插槽的定义 Slot到底是什么 如何使用插槽 回顾组件渲染的原理 插槽的初始化原理 解析插槽中的内容 作用域插槽原理 具名插槽原理 默认内容插槽的原理 Vue官方对插槽的定义 Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口. Slot到底是什么 那么Slot到底是什么呢?Slot其实是一个接受父组件传过来的插槽内容,然后生成VNode并返回的函数. 我们一般是使用 <

  • Vue3父子通讯方式及Vue3插槽的使用方法详解

    在Vue3中父子通讯方式 Vue3父传子(props) 父组件如下: <template> <div class="about"> <h1>This is an about page</h1> <children :num="num" age="30"></children> </div> </template> <script> impo

  • vue2.x中h函数(createElement)与vue3中的h函数详解

    目录 1. vue2.x的 h 函数(createElement) 2. vue3 h函数配置项 2.1 v-model实现(以下开始为官网实现) 2.2 v-on 2.3 事件修饰符 2.4 插槽 2.5 component 和 is 2.6 自定义指令 2.7 内置组件 2.8 渲染函数的返回值 2.9 JSX 总结 1. vue2.x的 h 函数(createElement) 使用方法及介绍:(参考官网提取) h函数第一个是标签名字 或者是组件名字,第二个参数是配置项,第三个参数是 inn

  • Python命令启动Web服务器实例详解

    Python命令启动Web服务器实例详解 利用Python自带的包可以建立简单的web服务器.在DOS里cd到准备做服务器根目录的路径下,输入命令: python -m Web服务器模块 [端口号,默认8000] 例如: python -m SimpleHTTPServer 8080 然后就可以在浏览器中输入 http://localhost:端口号/路径 来访问服务器资源. 例如: http://localhost:8080/index.htm(当然index.htm文件得自己创建) 其他机器

  • jenkins构建Docker 镜像实例详解

     jenkins构建Docker 镜像实例详解 前言:jenkins有Docker镜像,而之前我们说过使用jenkins打包Docker镜像,那么可否用jenkins的Docker镜像打包Docker镜像呢? 环境: CentOS 7     Docker 1.10.3 1.本机安装docker环境,并配置TCP访问接口 # vi /usr/lib/systemd/system/docker.service 修改ExecStart为: ExecStart=/usr/bin/docker daem

  • 最锋利的Visual Studio Web开发工具扩展:Web Essentials使用详解

    首先,从Extension Manager里安装:最新版本是19号发布的2.5版 然后重启你的VS开发环境,就可以使用它提供的方便功能了. Web Essentials对CSS.JavaScript和HTML都提供了很多快捷的功能支持,具体列表如下: CSS 即时预览Live Web Preview 每次修改的时候,都可以使用CTRL+ALT+Enter快捷键或者点击方案右键上的Live Web Preview选项来即时预览你修改的页面,每次修改完 HTML或者相应的CSS, Ctrl+S保存以

  • Spring之WEB模块配置详解

    Spring框架七大模块简单介绍 Spring中MVC模块代码详解 Spring的WEB模块用于整合Web框架,例如Struts1.Struts2.JSF等 整合Struts1 继承方式 Spring框架提供了ActionSupport类支持Struts1的Action.继承了ActionSupport后就能获取Spring的BeanFactory,从而获得各种Spring容器内的各种资源 import org.springframework.web.struts.ActionSupport;

随机推荐