vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue react中使用Web Components组件

在vue react中如何使用Web Components组件

作者:pg_li

这篇文章主要介绍了在vue react中如何使用Web Components组件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

在vue react中使用Web Components组件

1、web组件部分代码(git地址)

(function () {
    // 配置模板
    const getEemplate = () => {
        // 创建模板
        const template = document.createElement('template');
        // 给模板设置id 方便查找
        template.id = 'userCardTemplate';
        template.innerHTML = `
    <style>
        :host {
                display: flex;
                align-items: center;
                width: 450px;
                height: 180px;
                background-color: #d4d4d4;
                border: 1px solid #d5d5d5;
                box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
                border-radius: 3px;
                overflow: hidden;
                padding: 10px;
                box-sizing: border-box;
                font-family: 'Poppins', sans-serif;
            }
        .image {
                flex: 0 0 auto;
                width: 160px;
                height: 160px;
                vertical-align: middle;
                border-radius: 5px;
            }
        .container {
                box-sizing: border-box;
                padding: 20px;
                height: 160px;
            }
        .container > .name {
                font-size: 20px;
                font-weight: 600;
                line-height: 1;
                margin: 0;
                margin-bottom: 5px;
            }
        .container > .email {
                font-size: 12px;
                opacity: 0.75;
                line-height: 1;
                margin: 0;
                margin-bottom: 15px;
            }
        .container > .button {
                padding: 10px 25px;
                font-size: 12px;
                border-radius: 5px;
                text-transform: uppercase;
            }
     </style>
    <img class="image">
    <div class="container">
        <p class="name"></p>
        <p class="email"></p>
        <button class="button">Follow John</button>
    </div>
    `;
        return template;
    };
    // 讲模板放到dom结构中去
    const createEemplate = () => {
        document.body.appendChild(getEemplate());
    };
    createEemplate();
    class UserCard extends HTMLElement {
        constructor() {
            super();
            this.creatShadow();
            // 此处防止vue等框架类型的组件使用时 生命周期导致的参数异常 因此延迟绑定参数
            setTimeout(() => {
                this.creatContent();
            });
        }
        /**
         * 封闭内部dom
         */
        creatShadow() {
            this.shadow = this.attachShadow({mode: 'closed'});
        }
        /**
         * 创建内部显示内容
         */
        creatContent() {
            var templateElem = document.getElementById('userCardTemplate');
            var content = templateElem.content.cloneNode(true);
            content.querySelector('img').setAttribute('src', this.getAttribute('image'));
            content.querySelector('.container>.name').innerText = this.getAttribute('name');
            content.querySelector('.container>.email').innerText = this.getAttribute('email');
            this.shadow.appendChild(content);
        }
        /**
         * 当自定义元素第一次被连接到文档DOM时被调用
         * 相当于mounted
         */
        connectedCallback() {
            console.log('connectedCallback')
        }
        /**
         * 当自定义元素与文档DOM断开连接时被调用。
         * 与beforeDestroy类似
         */
        disconnectedCallback() {
            console.log('disconnectedCallback')
        }
        /**
         * 当自定义元素被移动到新文档时被调用。
         */
        adoptedCallback() {
            console.log('adoptedCallback')
        }
        /**
         * 暴露哪些属性可以被监听
         * @returns {string[]}
         */
        static get observedAttributes() {
            return ['image', 'name', 'email']
        }
        /**
         * 当自定义元素的一个属性被增加、移除或更改时被调用。
         */
        attributeChangedCallback() {
            console.log('attributeChangedCallback')
        }
    }
    window.customElements.define('user-card', UserCard);
})();
            /**
             * 自定义事件
            */
            this.dispatchEvent(new CustomEvent('submit', {
             detail: {
              data: {}
             }
            }));
            this.dispatchEvent(new CustomEvent('afterSubmit', {
             detail: {
              data: {}
             }
            }));

2、vue中使用部门代码

在public目录下得index.html中导入

<script src="./UserCard.js"></script>
<template>
  <div id="app">
    <user-card v-if="show" image="https://semantic-ui.com/images/avatar2/large/kristy.png"
               name="User Name"
               email="yourmail@some-email.com"
    ></user-card>
      <user-card
              image="https://semantic-ui.com/images/avatar2/large/kristy.png"
              name="test"
              email="yourmail@some-email.com"
      ></user-card>
    <button @click="onclick">
      测试
    </button>
  </div>
</template>
<script>
export default {
  data: function() {
    return {
      show: true
    }
  },
  name: 'App',
  mounted() {
  },
  methods: {
    // 测试web组件生命周期
    onclick() {
      this.show = !this.show;
    }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

3、在react中使用

// submit事件 在点击登录时触发,传递的登录信息在,detail字段中
// afterSubmit 在登录数据下发服务端后触发 用于处理登录后的路由跳转等逻辑
<user-card url="https://www.baidu.com/"
                  user="account"
                  password="password"
                  id="form"
                  style="background-image: url(/assets/background.jpg)"
                  body-style="right: 200px;"
                  title="系统">
    </user-card>
    <script>
        const form = document.querySelector('#form');
        form.addEventListener('submit', (data)=> {
            console.log(data)
        });
        form.addEventListener('afterSubmit', (data)=> {
            console.log(data)
        });
    </script>
/**
 * 处理react tsx中直接使用web components报错问题
 */
interface UserCardModuleProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
    title: string,
    ...
}
declare global {
    namespace JSX {
        interface IntrinsicElements {
            'user-card': UserCardModuleProps
        }
    }
}

4、在html中使用

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
</head>
<body>
<user-card
        image="https://semantic-ui.com/images/avatar2/large/kristy.png"
        name="User Name"
        email="yourmail@some-email.com"
></user-card>
<user-card
        image="https://semantic-ui.com/images/avatar2/large/kristy.png"
        name="test"
        email="yourmail@some-email.com"
></user-card>
<script src="./public/UserCard.js"></script>
<script >
</script>
</body>
</html>

组件化统一标准——Web Components

Web Components是什么

一句话概括,Web Components是一个Web组件标准。现在的前端开发几乎已经离不开组件化开发了,无论是vue中的模板语法还是react中的JSX,都是把结构、样式和逻辑封装成一个组件,采用组件复用来提高开发效率。

既然组件如此重要,Web Components就是提供浏览器底层的支持,不依赖各种框架的支持和webpack的编译,让我们也能使用组件。

Web Components通过一种标准化的非侵入的方式封装一个组件,每个组件能组织好它自身的HTML、CSS、JavaScript,并且不会干扰页面上的其他代码。

Web Components的组成

Web Components由以下四个部分组成:

clipboard.png

HTML templates

支持template标签和slot标签。slot标签支持动态替换模板中的HTML内容,它用name属性来作为唯一表示。template中的内容被插入到DOM之前,不会渲染,它可以放在document中的任何位置。

HTML Imports

改造一下上面的例子,将template的内容写到一个新的main.html文件中,然后通过link引入。

Shadow DOM

Shadow DOM提供了一种健壮的封装方式来做到页面节点的隔离,避免全局样式冲突,这也是Web Component的核心优势。

clipboard.png

Shadow DOM中设置的样式没有影响外部<p>标签的样式。

Custom elements

在custom element的构造函数中,可以指定多个不同的回调函数,它们将会在元素的不同生命时期被调用:

clipboard.png

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文