在vue中使用自定义元素

Web Components 是一组 web 原生 API 的统称,允许开发者创建可复用的自定义元素 (custom elements)。

创建自定义元素 defineCustomElement

Vue 提供了一个和定义一般 Vue 组件几乎完全一致的 defineCustomElement 方法来支持创建自定义元素。这个方法接收的参数和 defineComponent 完全相同。但它会返回一个继承自 HTMLElement 的自定义元素构造器:

<template>
    <ion-element :info="info" :obj.prop="obj"><div>1</div></ion-element>
</template>
<script lang="ts" setup>
  import { defineCustomElement, ref } from 'vue';

  const info = ref('ddd');
  const obj = ref({
    name: 'name',
  });
  const ionElement = defineCustomElement({
    props: {
      info: String,
      obj: Object,
    },
    emits: {},
    template: `<div class="test">{{ info }} - {{ obj.name }}<slot/></div>`,
    styles: [
      `.test { color: red; }`,
      '@import "http://localhost:3880/src/view/home/index.css";',
    ],
  });

  customElements.define('ion-element', ionElement);
</script>

默认情况下,Vue 会将任何非原生的 HTML 标签优先当作 Vue 组件处理,而将“渲染一个自定义元素”作为后备选项。要让 Vue 知晓特定元素应该被视为自定义元素并跳过组件解析

vite配置
// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          // 将所有带短横线的标签名都视为自定义元素
          isCustomElement: (tag) => tag.includes('ion-')
        }
      }
    })
  ]
}

在vue这个构建中不支持运行时编译 需要配置你的 bundler 别名 vue: vue/dist/vue.esm-bundler.js

resolve: {
  alias: {
    'vue': 'vue/dist/vue.esm-bundler.js',
    '@': resolve(__dirname, 'src')
  }
}

正确渲染

image.png

props

所有使用props选项声明的props都会作为属性定义在改自定义元素上

事件

通过 this.$emit 或者 setup 中的 emit 触发的事件都会通过以 CustomEvents 的形式从自定义元素上派发。额外的事件参数 (payload) 将会被暴露为 CustomEvent 对象上的一个 detail 数组。

插槽

在一个组件中,插槽将会照常使用 <slot/> 渲染。然而,当使用最终的元素时,它只接受原生插槽的语法

  • 不支持作用域插槽

  • 当传递具名插槽时,应使用 slot attribute 而不是 v-slot 指令:

<my-element>
  <div slot="named">hello</div>
</my-element>

将 SFC 编译为自定义元素

defineCustomElement 也可以搭配 Vue 单文件组件 (SFC) 使用
要选用此模式,只需使用 .ce.vue 作为文件拓展名即可。

// item.ce.vue
<template>
  <h3> custom web components </h3>
  <ul>
    <li v-for="item in list" :key="item.name">
      姓名:{{ item.name }} - 年龄:{{ item.age }}
    </li>
  </ul>
</template>

<script lang="ts" setup>
  import { defineProps } from 'vue';

  defineProps({
    list: {
      type: Array,
      default: () => [
        { name: 'y', age: 10 },
        { name: 'tom', age: 12 },
      ],
    },
  });
</script>

<style scoped>
  li {
    line-height: 24px;
  }
</style>


 import iconListCe from './item.ce.vue';

  const IconList = defineCustomElement(iconListCe);

   customElements.define('icon-list', IconList);
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容