精华内容
下载资源
问答
  • Component和PureComponent的区别
    万次阅读 多人点赞
    2019-02-23 17:35:58


    ReactNative系列-文章

    Component和PureComponent的区别

    介绍

    React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过props和state的浅对比来实现 shouldComponentUpate()。

    在PureComponent中,如果包含比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断,导致界面得不到更新。

    如果定义了 shouldComponentUpdate(),无论组件是否是 PureComponent,它都会执行shouldComponentUpdate结果来判断是否 update。如果组件未实现 shouldComponentUpdate() ,则会判断该组件是否是 PureComponent,如果是的话,会对新旧 props、state 进行 shallowEqual 比较,一旦新旧不一致,会触发 update。

    浅对比:通过遍历对象上的键执行相等性,并在任何键具有参数之间不严格相等的值时返回false。 当所有键的值严格相等时返回true。shallowEqual

    区别点:

    1. PureComponent自带通过props和state的浅对比来实现 shouldComponentUpate(),而Component没有。

    PureComponent缺点

    1. 可能会因深层的数据不一致而产生错误的否定判断,从而shouldComponentUpdate结果返回false,界面得不到更新。

    PureComponent优势

    1. 不需要开发者自己实现shouldComponentUpdate,就可以进行简单的判断来提升性能。

    为什么PureComponent比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断?

    JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如 foo={a: 1}; bar=foo; bar.a=2 你会发现此时 foo.a 也被改成了 2。

    为了解决这个问题,一般的做法是使用 shallowCopy(浅拷贝)或 deepCopy(深拷贝)来避免被修改,但这样做造成了 CPU 和内存的浪费。

    let foo = {a: {b: 1}};
    let bar = foo;
    bar.a.b = 2;
    console.log(foo.a.b);  // 打印 2
    console.log(foo === bar); // 打印 true
    

    可以在fb的shallowEqual方法源码中看到,如下,浅对比只是用Object.is()对Object的value做了一个基本数据类型的比较。

    
    function is(x: mixed, y: mixed): boolean {
      // SameValue algorithm
      if (x === y) { // Steps 1-5, 7-10
        // Steps 6.b-6.e: +0 != -0
        // Added the nonzero y check to make Flow happy, but it is redundant
        return x !== 0 || y !== 0 || 1 / x === 1 / y;
      } else {
        // Step 6.a: NaN == NaN
        return x !== x && y !== y;
      }
    }
    
    function shallowEqual(objA: mixed, objB: mixed): boolean {
      if (is(objA, objB)) {
        return true;
      }
    
      if (typeof objA !== 'object' || objA === null ||
          typeof objB !== 'object' || objB === null) {
        return false;
      }
    
      const keysA = Object.keys(objA);
      const keysB = Object.keys(objB);
    
      if (keysA.length !== keysB.length) {
        return false;
      }
    
      // Test for A's keys different from B.
      for (let i = 0; i < keysA.length; i++) {
        if (
          !hasOwnProperty.call(objB, keysA[i]) ||
          !is(objA[keysA[i]], objB[keysA[i]])
        ) {
          return false;
        }
      }
    
      return true;
    }
    

    我们先来对is()函数进行分析:

    在js中 ‘===’ 可以判断数据类型是否相等,但其实这样方式也并不十分严谨,例如

    +0 === -0; // js 打印true
    NaN === NaN; // js 打印false
    

    我们希望上述的判断结果,+0和-0为false,NaN与NaN为true,这时候可以用这种方式

    1/+0 // 结果为Infinity
    1/-0 // 结果为-Infinity
    Infinity === -Infinity; // false
    
    解决 NaN === NaNfalse,可以通过NaN和自身不相等的特性来解决
    x !== x && y !== y
    

    所以is()函数首先是通过 ‘===’ 来对数据类型进行比较,然后解决+0/-0和NaN的比较问题。

    接下来分析shallowEqual()函数

    function shallowEqual(objA: mixed, objB: mixed): boolean {
      // 首先对两个基本数据类型进行比较
      if (is(objA, objB)) {
        return true;
      }
    
      // 判断两个数据都为object的情况
      if (typeof objA !== 'object' || objA === null ||
          typeof objB !== 'object' || objB === null) {
        return false;
      }
    
      // 获得所有的key
      const keysA = Object.keys(objA);
      const keysB = Object.keys(objB);
    
      // 判断两者key的数量是否一致
      if (keysA.length !== keysB.length) {
        return false;
      }
    
      // 如果key数量相同,使用一层for循环去比较
      for (let i = 0; i < keysA.length; i++) {
        if (
          // 判断对象B中是否包含对象A的key,即两者的keys是否一致
          !hasOwnProperty.call(objB, keysA[i]) ||
          // 通过is()函数对比A和B的key对应的数据
          !is(objA[keysA[i]], objB[keysA[i]])
        ) {
          return false;
        }
      }
    

    下面以组件的使用来举例:

    例如:

    class ChildComponent extends React.PureComponent {
      render() {
        return(
          <div>
            {this.props.numbers}
          </div>
        )
      }
    }
    class MainComponent extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.state = {
          numbers: [0]
        }
      }
      handleClick() {
        const arr = this.state.numbers;
        arr.push(1);
        this.setState({
          numbers: arr
        })
        console.log(this.state.numbers)
      }
      render() {
        <div>
          <button onClick={this.handleClick} />
          <ChildComponent numbers={this.state.numbers}/>
        </div>
      }
    }
    

    然而在MainComponent中去修改numbers时,ChildComponent并没有得到刷新。原因在于js使用的是引用赋值,新的对象简单引用了原始对象,改变新对象虽然影响了原始对象,但对象的地址还是一样,使用===比较的方式相等。而在PureComponent中,会被判定prop相等而不触发render()。

    避免此类问题最简单的方式是,避免使用值可能会突变的属性或状态,而是使用副本来返回新的变量。

    handleClick() {
      this.setState(prevState => ({
        words: [...prevState.words, 'marklar'],
      }));
    };
    
    

    另外一种方式是使用Immutable.js

    更多相关内容
  • componentone注册码

    2018-10-12 11:56:27
    componentone注册码
  • MX Component,c#,winfrom,.net,控件读写三菱PLC-FX5U,在安装好三菱的MX Component 工具 并配置好通道等参数之后,使用c# winfrom开发 PLC的通讯,包括单个值读取,批量读取,轮询等等。 以及写入等操作
  • 著名的Delphi TMS Component Pack v8.3.4.0 full source D7~XE10.2控件组,含全部源码,支持 D7~ XE10.2 Tokyo
  • MX Component Version 4 编程手册 + MX Component Version 4 操作手册 压缩打包 , 希望对有需要的朋友有帮助。
  • c#通过MX component连接三菱PLC源代码

    热门讨论 2018-01-05 15:44:56
    上位机安装MX component后,利用c#调用MX component,以达到和三菱PLC进行通讯的目的
  • Component

    千次阅读 2020-06-15 16:25:45
    请求此 Component 获取输入焦点,并且此 Component 的顶层祖先成为获得焦点的 Window。此 Component 对于所要许可的请求而言必须是不可显示的、可聚焦的和可见的并且其所有祖先(除了顶层 Window 以外)必须是可见的...

    请求此 Component 获取输入焦点,并且此 Component 的顶层祖先成为获得焦点的 Window。此 Component 对于所要许可的请求而言必须是不可显示的、可聚焦的和可见的并且其所有祖先(除了顶层 Window 以外)必须是可见的。此方法会尽力完成该请求;但是在某些情况下可能无法完成。在此 Component 接收 FOCUS_GAINED 事件前,开发人员永远不能假定此 Component 是焦点所有者。如果由于此 Component 的顶层 Window 没有成为获得焦点的窗口而拒绝了此请求,则记住此请求,并在后来用户使窗口成为获得焦点的窗口时许可此请求。
    此方法不能用于为根本不是 Component 的内容设置焦点所有者,应该使用 KeyboardFocusManager.clearGlobalFocusOwner()。

    因为此方法的焦点行为与平台有关,所以强烈建议开发人员在可能时使用 requestFocusInWindow。

    注:并不是所有的焦点传输都将导致防止调用此方法。同样地,组件可以在没有调用此方法或 Component 的其他任何方法的情况下接收焦点。

    从以下版本开始:
    JDK1.0

    展开全文
  • ComponentOne Studio for WinForms 2014 V3

    热门讨论 2014-11-28 09:05:36
    ComponentOne Studio for WinForms 功能强大,覆盖全面,WinForms 平台全能用户界面开发控件套包; ComponentOne Studio for WinForms 包含超过65个 .NET 控件,其中,还有一些是 WinForms 所独有的。它拥有敏捷的...
  • 通过使用MX component 在VS2010环境下使用C#开发数据采集软件,您可去三菱官网下载MX Component的最新版本。如果您使用的是三菱其它型号的PLC,改变控件的某些属性即可。
  • ComponentOne2011破解版

    热门讨论 2012-02-15 09:22:03
    ComponentOne2011破解版  ComponentOne Studio是美国ComponentOne公司开发的控件系列产品名,支持WinForms、WPF、ASP.NET、Silverlight、iPhone、Mobile和ActiveX等7个开发平台。  ComponentOne Studio基于最新的...
  • 程序说明:程序是使用C#基于以太网来读写三菱PLC数据的,程序中使用的是ActUtlType控件与PLC进行通信,将读取的数据显示出来。这只是一个演示程序,对初学者会有很大帮助。
  • linux component组件架构分析

    千次阅读 2020-09-19 13:35:02
    component 组件系统架构分析 背景介绍 任何架构的提出都是有其现实应用背景的,都是为了解决一些现实问题。而component系统架构的提出就是出于这样一种现实需求:构建功能系统! 系统就是各种功能单元(组件)的有序...

    Linux component 组件系统架构分析

    原创文章,转载请标明出处。

    背景介绍

    任何架构的提出都是有其现实应用背景的,都是为了解决一些现实问题。而component系统架构的提出就是出于这样一种现实需求:构建功能系统!

    系统就是各种功能单元(组件)的有序结合。一个系统,只有集齐了它的所有组件才能正常工作。
    可以打个比方:一辆车就是一个系统,它由各种组件–发动机,变速箱,中控台,车轮等构成。

    一辆车,只装上发动机,或变速箱。是不能工作的,必须安装了所有的组件,才能开始发动。

    而发动的过程,也是有顺序要求的,如先采离合,再挂当(变速箱初始化),再踩油门(发动机初始化),车轮再开始转动。(有序)

    所以component架构构建功能系统就包括两方面的作用:

    1. 保证系统安装了所有的组件
    2. 规定了系统各组件初始化的顺序

    component架构在linux内核中现在主要的应用是用来构建display-subsystem,一个显示子系统,由LCD控制器(vop),接口控制器(mipi,lvds,hdmi),液晶背光,电源等多个独立的功能单元构成。而把这些功能单元构成一个系统,就需要这些功能单元间有一定的协同配合。

    如在扫描设备树时,每一个设备节点依次被注册到系统中(一般用platform_device_register)。而只有当所有显示子系统相关的设备节点都注册到系统中时,整个显示系统才能正常工作。

    如果没有component架构的参与,在用platform_device_register函数注册每个设备节点时,在其驱动的probe函数中。就已经执行了一系列的初始化工作,而此时系统相关的其他设备节点可能还没有注册到内核中,这样可能就会导致一些问题出现。

    在component架构的参下,可以保证在显示子系统的所有功能单元都注册后,才按照一定顺序执行初始化操作。

    架构分析

    component架构的实现位于drivers/base/componet.c
    对系统组件架构有了概念上的理解后,分析架构就比较简单了。

    数据结构

    component系统组件架构涉及到如下几个数据结构:
    struct component用来表示系统组件。
    struct master表示需要构建的系统。
    struct component_match用来匹配系统需要的组件。并规定了组件的初始化顺序。
    component 架构上述结构可以用拼乐高积木的过程来理解:
    一个一个形态各异的积木就用struct component来表示,而struct master就是
    要拼接成的东西(系统)(例如想拼成一辆车,一只恐龙,或一个房子)。而struct component_match就是你手里的图纸。根据图纸,你就可以在一个个积木(component)中,找出需要的积木,然后拼成一个想要的作品(master)。
    根据上面的理解我们在详细的看一下这些结构体中的内容就比较好理解了.

    1. component
    struct component {
    	struct list_head node;        
    	struct list_head master_node;
    	struct master *master;
    	bool bound;
    	const struct component_ops *ops;
    	struct device *dev;
    };
    

    node:用于加入到component_list链表,该链表保存了注册到组件系统架构中的所有component
    master_node:该组件如果最终被某个master选中,则通过此成员用于加入到该master的components链表中,便于后续该master来遍历其组件。
    master: 组件所属的master
    bound: 表示组件是否已经执行了bind操作
    ops: 组件可执行的初始化操作。

    1. master
    struct master {
    	struct list_head node;
    	struct list_head components;
    	bool bound;
    	const struct component_master_ops *ops;
    	struct device *dev;
    	struct component_match *match;
    };
    

    node:同compnent中node作用一样,用于向组件系统架构中注册master。
    components:用于保存该系统(master)下的组件。
    ops:master可执行的初始化和退出操作。
    match:该master用到的compnent_match,master 应用该match在组件系统架构component_list链表中找到适配于自己的component组件。

    3.component_match

    我们之前说过组件系统的两方面作用,即保证系统安装了所有组件和保证组件的初始化顺序。compnent_match是实现这两个作用的核心数据结构! component_match中用compare结构体数组表示一个系统(master)中需要的所有组件。每个数组条目代表了一个需要安装的组件。而一个系统中所需的组件数量是不定的,所以采用了零长数组的方式,用于动态扩展组件数量。 而master又是如何通过compnent_match匹配到component的呢?答案就是通过每个compare[]数组元素中的fn函数,int (*fn)(struct device *, void *)函数指针指定了匹配的规则(方法)*data 中保存了fn用到的匹配数据。

    struct component_match {
    	size_t alloc;
    	size_t num;
    	struct {
    		void *data;
    		int (*fn)(struct device *, void *);
    	} compare[0];
    };
    

    alloc:用于记录分配的compare数组大小。
    num:用于记录系统实际需要的组件(compnents)数量。当num等于alloc时,会引发compare数组的空间扩展分配。

    我们再回到最初的问题:

    如何保证系统安装了所有组件?

    答案即是通过component_match的compare数组。master只有在匹配到了compare数组中指定的所有组件后才会执行初始化函数component_master_ops->bind

    而又是如何指定各个组件的执行顺序呢?

    同样也是通过compare数组,compare数组元素的顺序即指定了加入master 的component链表的顺序,进而决定了component组件初始化的顺序。

    4.component_master_ops master执行的操作。

    struct component_master_ops {
    	int (*add_components)(struct device *, struct master *);
    	int (*bind)(struct device *);
    	void (*unbind)(struct device *);
    };
    

    5.component_ops 组件可以执行的操作。

    struct component_ops {
    	int (*bind)(struct device *, struct device *, void *);
    	void (*unbind)(struct device *, struct device *, void *);
    };
    

    组件系统工作流程

    组件系统大致包括如下操作:

    1. 向组件系统注册component
      注册的component被保存到static LIST_HEAD(component_list);静态链表中。此操作通过int component_add(struct device *dev, const struct component_ops *ops)函数实现。每次向系统注册一个组件时,都会遍历系统的master链表,尝试把该组件绑定到合适的master中去。这个过程是通过master扫描其component_mach,并遍历系统component_list,找出符合mach匹配函数的组件进行绑定。
      当一个master找到了其所有的组件后会执行其初始化函数。
      ret = master->ops->bind(master->dev);

    2. 构建component_match
      component_match作为master查找component的地图,需要在master注册到系统前来构建。系统通过component_match_add函数逐一添加compare条目,用于匹配每一个comonent,这个过程也确定了后续每个component的初始化过程。

    3. 向组件系统注册master。
      注册的master被保存到组件系统架构的static LIST_HEAD(masters)静态链表中。一般通过component_master_add_with_match函数实现。此函数同时会遍历系统component_list链表,找出符合match的组件进行绑定。
      当一个master找到了其所有的组件后会执行其初始化函数。
      ret = master->ops->bind(master->dev);

    4. bind执行
      系统和系统组件初始化函数执行的时机是什么呢?
      无论是通过component_add函数向组件系统中注册component,还是通过component_master_add_with_match函数向系统中注册master时,当mastr安装了其所有的componet后都会执行master->ops->bind(master->dev);操作,在此操作中一般会执行component_bind_all函数,开始执行各组件的初始化:component->ops->bind

    代码分析

    /*
     * Add a component to be matched.
     *
     * The match array is first created or extended if necessary.
     */
    void component_match_add(struct device *dev, struct component_match **matchptr,
    	int (*compare)(struct device *, void *), void *compare_data)
    {
    	struct component_match *match = *matchptr;
    
    	if (IS_ERR(match))
    		return;
    
    	/*当第一次分配match或mactch中compare数组已经满了时,进行match的空间分配*/
    	if (!match || match->num == match->alloc) {
    		size_t new_size = match ? match->alloc + 16 : 15;//如果是第一次分配compare数组size 为15,如果不是第一次分配,会用原来大小alloc+16
    
    		match = component_match_realloc(dev, match, new_size);//new_size表示的是分配的compare数组的大小。
    
    		*matchptr = match;
    
    		if (IS_ERR(match))
    			return;
    	}
    
    	/*下面初始化了一个compare数组元素,表示增加了一个组件的匹配项*/
    	match->compare[match->num].fn = compare;
    	match->compare[match->num].data = compare_data;
    	match->num++;//可以看到num记录了match中增加的组件数。最终作为master需要的组件数。
    }
    
    static struct component_match *component_match_realloc(struct device *dev,
    	struct component_match *match, size_t num)
    {
    	struct component_match *new;
    
    	if (match && match->alloc == num)
    		return match;
    	
    	/*分配component_match空间,num指定了compare结构体数组的大小*/
    	new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
    	if (!new)
    		return ERR_PTR(-ENOMEM);
    	
    	if (match) {
    		memcpy(new, match, component_match_size(min(match->num, num)));
    		devm_kfree(dev, match);//扩展match时执行的是重新分配。释放了原来的空间。
    	} else {
    		new->num = 0;
    	}
    	
    	new->alloc = num;//记录了分配的compare数组size
    	
    	return new;
    }
    
    /*向comonent架构系统中注册一个组件*/
    int component_add(struct device *dev, const struct component_ops *ops)
    {
    	struct component *component;
    	int ret;
    
    	component = kzalloc(sizeof(*component), GFP_KERNEL);//分配component
    	
    	if (!component)
    		return -ENOMEM;
    	
    	component->ops = ops;//对compnent进行初始化,指定了组件的操作函数
    	component->dev = dev;
    	
    	dev_dbg(dev, "adding component (ops %ps)\n", ops);
    	
    	mutex_lock(&component_mutex);
    	list_add_tail(&component->node, &component_list);//把组件加入链表component_list
    	
    	ret = try_to_bring_up_masters(component);//遍历注册的每个master,并尝试把compnent绑定之。
    	if (ret < 0) {
    		list_del(&component->node);
    	
    		kfree(component);
    	}
    	mutex_unlock(&component_mutex);
    	
    	return ret < 0 ? ret : 0;
    }
    
    int component_master_add_with_match(struct device *dev,
    	const struct component_master_ops *ops,
    	struct component_match *match)
    {
    	struct master *master;
    	int ret;
    
    	if (ops->add_components && match)
    		return -EINVAL;
    	
    	if (match) {//根据compare数组的大小重新分配match空间
    		/* Reallocate the match array for its true size */
    		match = component_match_realloc(dev, match, match->num);
    		if (IS_ERR(match))
    			return PTR_ERR(match);
    	}
    	
    	/*master初始化并注册*/
    	master = kzalloc(sizeof(*master), GFP_KERNEL);
    	if (!master)
    		return -ENOMEM;
    	
    	master->dev = dev;
    	master->ops = ops;
    	master->match = match;
    	INIT_LIST_HEAD(&master->components);
    	
    	/* Add to the list of available masters. */
    	mutex_lock(&component_mutex);
    	list_add(&master->node, &masters);//加入链表
    	
    	ret = try_to_bring_up_master(master, NULL);//开始查找组件,进而启动系统。
    	
    	if (ret < 0) {
    		/* Delete off the list if we weren't successful */
    		list_del(&master->node);
    		kfree(master);
    	}
    	mutex_unlock(&component_mutex);
    	
    	return ret < 0 ? ret : 0;
    }
    
    static int try_to_bring_up_masters(struct component *component)
    {
    	struct master *m;
    	int ret = 0;
    
    	list_for_each_entry(m, &masters, node) {
    		ret = try_to_bring_up_master(m, component);
    		if (ret != 0)
    			break;
    	}
    	
    	return ret;
    }
    
    /*
     * Try to bring up a master.  If component is NULL, we're interested in
     * this master, otherwise it's a component which must be present to try
     * and bring up the master.
     *
     * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
     */
    static int try_to_bring_up_master(struct master *master,
    	struct component *component)
    {
    	int ret;
    
    	if (master->bound)
    		return 0;
    
    	/*
    	 * Search the list of components, looking for components that
    	 * belong to this master, and attach them to the master.
    	 */
    	if (find_components(master)) {
    		/* Failed to find all components */
    		ret = 0;
    		goto out;
    	}
    
    	if (component && component->master != master) {//如果component !=NULL,component必须属于master。才会执行后面的系统初始化。
    		ret = 0;
    		goto out;
    	}
    
    	if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {//设备模型中的设备资源管理相关操作,用于管理设备的资源组。这里不具体介绍。
    		ret = -ENOMEM;
    		goto out;
    	}
    
    	/* Found all components */
    	ret = master->ops->bind(master->dev);//如果绑定了所有的组件,开始执行系统初始化。一般在此函数中会继续调用component_bind_all函数执行组件的初始化。
    	if (ret < 0) {
    		devres_release_group(master->dev, NULL);
    		dev_info(master->dev, "master bind failed: %d\n", ret);
    		goto out;
    	}
    
    	master->bound = true;//表示系统已经绑定了所有组件,并执行了初始化。
    	return 1;
    
    out:
    	master_remove_components(master);
    
    	return ret;
    }
    
    static int find_components(struct master *master)
    {
    	struct component_match *match = master->match;
    	size_t i;
    	int ret = 0;
    
    	if (!match) {
    		/*
    		 * Search the list of components, looking for components that
    		 * belong to this master, and attach them to the master.
    		 */
    		return master->ops->add_components(master->dev, master);
    	}
    	
    	/*
    	 * Scan the array of match functions and attach
    	 * any components which are found to this master.
    	 */
    	for (i = 0; i < match->num; i++) {//遍历了component_match中的compare数组。对比每一个数组项,绑定component到master
    		ret = component_master_add_child(master,
    						 match->compare[i].fn,
    						 match->compare[i].data);
    		if (ret)
    			break;
    	}
    	return ret;
    }
    
    展开全文
  • MX Component 4 安装包

    热门讨论 2013-05-28 13:22:21
    MX Component 4 安装包
  • web component指南

    千次阅读 2020-09-13 20:59:01
    web component 什么是web component? web component是web原生提供的封装组件的方式,让开发者定义一些可重复使用的自定义元素。主要包含custom elements、shadow dom、html templates部分,分别用于注册自定义元素...

    web component

    什么是web component?

    web component是web原生提供的封装组件的方式,让开发者定义一些可重复使用的自定义元素。主要包含custom elementsshadow domhtml templates部分,分别用于注册自定义元素、提供shadow-dom接口,为自定义元素的样式和脚本提供一个隔离的环境、通过templateslot编写自定义元素的结构模板。

    如何开发一个web component?

    一个web component就是一个我们可以在正常dom中使用的自定义元素。自定义元素只需要包含标记结构、样式以及脚本三个部分,最后再对新的自定义元素进行一个注册。

    首先是注册,通过CustomElementRegistry.define()方法完成,CustomElementRegistry包含自定义元素的相关功能,可以通过Window.customElements访问它的引用。例如:

    customElements.define('element-a', ElementA, { extends: 'p' })
    

    可以看到define函数包含三个参数:

    1.自定义元素名
    2.包含自定义元素内容的类
    3.可选参数,包含extends属性的对象,指定了创建的元素继承自哪个内置元素,可以继承任意的内置元素

    第三个可选参数,需要解释下,我们注册的自定义元素分为两类。

    第一种是独立的元素,不继承其他内置的html元素,此时,define函数不传递第三个参数,元素的类继承自HTMLElment类。这样注册的自定义元素,使用方式简单,像普通的html元素一样,例如:<element-a />

    第二种是继承自某个内置的html元素,例如p。此时,第三个参数应该是{ extends: 'p' }。同时元素的类也应该继承HTMLParagraphElement类。使用方式是<p is="element-a" />或者在js中document.createElement("p", { is: "element-a" })

    其中自定义元素的类是最重要的部分,我们会在内部定义它的结构、样式和行为。常见结构如下:

    class ElementA extends HTMLElement {
        constructor() {
            // 必须首先调用 super 方法
            super();
    
            // 元素的功能代码写在这里
            // ...
        }
    
        connectedCallback() {
            // 自定义元素首次插入文档dom时调用
            // 相较于constructor只会执行一次,这个生命周期每次将节点连接到dom时都会调用
            // 可能会执行多次(比如同一个自定义元素remove, append多次)
        }
    
        disconnectedCallback() {
            // 自定义元素从文档中删除时,调用
        }
    
        adoptedCallback() {
            // 自定义元素移动到新的文档
            // 比如使用 adoptNode 方法在多iframe下移动元素
        }
    
        attributeChangedCallback(name, oldVal, newVal) {
            // 属性变更时调用:三个参数对应属性名,旧值,新值
        }
    }
    

    在自定义元素类中定义内容需要借助shadow-dom接口的能力,它提供了封装的能力,将标记结构、样式和行为隐藏到一个独立的dom中,我们操作shdaow-dom和操作常规dom一样(新添加子节点、修改属性等),但是在shadow-dom中的元素和外部的元素互不影响,不能通过document.querySelector方法拿到内部的元素,外部的css样式也不会影响shadow-dom中定义的元素。我们会在里面定义自定义元素的结构,最后将其附加到常规的dom树中。

    浏览器内置的一些html元素也有使用它的功能,例如:video input-range等,在 Chrome 中,开发者可以启用开发者工具的Show user agent shadow DOM选项,就能看到这些隐藏的结构。

    在这里插入图片描述
    在这里插入图片描述

    shadow-dom和dom的关系如下图所示:

    在这里插入图片描述

    • shadow host:一个常规的dom节点,是shadow-dom的挂载节点,比如我们的自定义元素
    • shadow tree:shadow-dom内部的dom树
    • shadow boundary:shadow-dom结束的地方,也是常规dom开始的地方
    • shadow root: shadow-tree的根节点

    在自定义元素中我们通过Element.attachShadow将一个shadow root附加到任意元素上:

    const shadowRoot = elementRef.attachShadow({mode: 'open'})
    // 参数mode有两个值
    // open表示可以通过element.shadowRoot访问shadow-dom
    // closed表示不可以从外部获取shadow dom(例如内置元素video)
    

    接着我们就可以为自定义元素添加内容:

    const para = document.createElement('p')
    para.innerHTML = '这是我的自定义元素'
    shadowRoot.appendChild(para)
    

    然后可以使用多种方式给shadow-dom添加样式:

    1.创建style元素

    const style = document.createElement('style');
    
    style.textContent = `
    p {
        color: #ccc;
    }
    `
    shadowRoot.appendChild( style )
    

    2.通过link元素使用外部的样式

    const linkElem = document.createElement('link')
    linkElem.setAttribute('rel', 'stylesheet')
    linkElem.setAttribute('href', 'style.css')
    
    shadow.appendChild(linkElem)
    

    3.使用template,在template中加入一个style节点

    最后也可以像常规dom一样设置一些交互事件,甚至定制一些专属的属性,例如我们自定义一个card元素,通过text属性指定card的内容:

    <custom-card text="这是我的card组件" />
    
    <script>
        class Card extends HTMLElement {
            constructor() {
                super()
                const shadowRoot = this.attachShadow({ mode: 'open' })
                const text = this.getAttribute('text')
                const p = document.createElement('p')
                p.innerHTML = text
                shadowRoot.appendChild(p)
            }
        }
        customElements.define('custom-card', Card)
    </script>
    

    最后介绍下模板和slot的使用,上面的方式定义样式和页面结构太麻烦,也不利于复用,我们可以切换为模板和slot的方式,

    我们可以先在template中定义内容和样式,然后添加到shadow dom中:

    class extends HTMLElement {
        constructor() {
            super();
            let template = document.getElementById('element-tmp')
            let templateContent = template.content
    
            const shadowRoot = this.attachShadow({mode: 'open'})
                .appendChild(templateContent.cloneNode(true))
        }
    }
    

    另外开发者可以通过slot插槽的方式来传递自定义组件需要的内容(类似于vue),灵活度更高,同时插槽中的内容会受到外部样式的影响。插槽分为命令插槽和默认插槽。

    // 相同名称的多个插槽内容会被放在一起
    <slot-exp>
        <div>未命名插槽内容1</div>
        <div>未命名插槽内容2</div>
        <div slot="content-a">content-a</div>
        <div slot="content-a">content-a</div>
    </slot-exp>
    
    <template id="slot-exp--tmp">
        <div class="slot-exp">
            <div>
                <h2>未命名插槽:</h2>
                <slot />
            </div>
            <div>
                <h2>具名插槽:</h2>
                <slot name="content-a" />
            </div>
            <slot name="content-b">插槽 content-b 默认填充</slot>
        </div>
    </template>
    
    <script>
        class SlotExp extends HTMLElement {
            constructor() {
                super()
    
                this.attachShadow({ mode: 'open' })
                const tmp = document
                    .getElementById('slot-exp--tmp')
                    .content
                this.shadowRoot.appendChild( tmp.cloneNode(true) )
            }
        }
        customElements.define('slot-exp', SlotExp)
    </script>
    

    web component api的兼容性

    开发者可以到can i use搜索web component查看支持程度,支持度还不错。对于一些还未支持的浏览器,也有polyfills使用。

    总结

    相较于目前流行的react、vue、ng等前端框架,web component是浏览器原生提供的不添加任何依赖的组件封装方式,同时提供了一个隔离的运行环境,目前流行的微前端框架的实现方式之一就是借助了web component的隔离能力。还可以到https://www.webcomponents.org/查看一些开源的web component

    thx

    • https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
    • https://javascript.info/slots-composition
    • https://zhuanlan.zhihu.com/p/42370005
    • https://juejin.im/post/6844903876127113230
    展开全文
  • Vue源码学习 - 组件化一 createComponent

    千次阅读 多人点赞 2020-12-01 22:22:06
    Vue源码学习 - 组件化组件化createComponent 学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:《Vue.js2.0 源码揭秘》、 黄轶老师拉钩教育教程地址:《Vue.js 3.0 核心源码解析》 这里分析的源码是...
  • ECS的简单入门(三):Component

    千次阅读 2020-07-06 17:04:00
    通过上一篇文章我们已经大致了解了ECS的整体概念,这篇文章我们就先来深入的了解下Component
  • 微信开放平台-获取授权事件接收URL的component_verify_ticket
  • linux kernel component框架分析

    千次阅读 2019-12-18 20:37:45
    kernel中的component是为了subsystem能够按照一定的顺序初始化设备而提出的架构。 subsystem中由较多设备模块组成,而内核加载每个模块时间不定。则需要component来保证需最后初始化的设备加载前,所需设备全部加载...
  • 提到PureComponent,应该并不是react与生俱来就有的,而应该是在15.3版本之后才出现的,主要是为了取代之前的PureRenderMixin。所以对于几年不怎么接触react的我来说,当提到PureComponent的时候,还是有那么些许的...
  • ROS2编程基础课程--Component

    千次阅读 2019-09-12 15:28:34
    $ ros2 component load /ComponentManager composition composition::Listener Loaded component 2  into '/ComponentManager'  container node as '/listener'   The  ros2  command line utility...
  • 著名的 Delphi 控件组。含全部源码,支持 Delphi XE10.2 Tokyo
  • 细谈 vue - component

    千次阅读 2019-09-12 14:36:34
    const child = vnode.componentInstance = oldVnode.componentInstance updateChildComponent( child, options.propsData, // updated props options.listeners, // updated listeners vnode, // new parent ...
  • 上位机通过MX component version4 组件与三菱PLC通信解决办法第一节:MX Component Version4软件与手册下载第二节:MX Component Version4 软件的使用与通信测试2.1 PLC以太网地址设置:2.11 查询电脑的IP地址:2.12...
  • vue内置动态组件component使用详解

    千次阅读 2022-03-05 23:55:20
    1 动态组件介绍 component是vue内置组件,主要作用为动态渲染组件,基本用法如下: <!-- 动态组件由 vm 实例的 `componentName` property 控制 --> <component :is="componentName"></component> 其中,根据绑定的is...
  • 已知vue的template语法中,动态组件是这么写的 换成jsx写法 这样似乎行不通,运行会报错: Unknown custom element: - did you register the component correctly…… 完整代码如下: import { Component, Vue } ...
  • vue组件component详解

    千次阅读 2020-12-25 09:14:18
    vue组件component详解 组件介绍 组件: ​ 组件是拥有一定功能多个html标签的集合体,是对html标签的封装。 好处: ​ 模板中为了实现一个(例如分页)效果,需要绘制20个html标签,如果使用组件,就设置一个标签就...
  • vue-component

    千次阅读 2017-11-08 11:47:41
    vue-componentvue组件简介组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树 什么是组件 组件可以扩展HTML元素...
  • PureComponentComponent的区别

    千次阅读 2019-06-27 11:17:49
    PureComponent PureComponent是组件开发中的重要概念,组件开发人员需要深度理解相关概念。 组件:里面写的是html PureComponent大组件big PureComponent 大组件big PureComponent里面有三个小组件:小组件a、小组件b...
  • 谈一谈创建React Component的几种方式

    千次阅读 2019-03-18 14:07:38
    当我们谈起React的时候,多半会将注意力集中在组件之上,思考如何将页面划分成一个个组件,以及如何编写可复用的组件。...但学习了ES6的语法后,又知道了可以利用继承,通过extends React.component来创建组...
  • 前端框架系列之(vue-class-component

    千次阅读 2020-06-14 22:58:23
    简介: 说到函数式组件跟类组件在react官方就有提供,具体差异的话大家可以自行查阅react开发文档,下面我们看一下在react中怎么使用这...class Welcome extends React.Component { render() { return ( <h1>

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,222,633
精华内容 489,053
关键字:

component

友情链接: javapintu.rar