精华内容
下载资源
问答
  • 我试图在javascript中调用耗时的函数之前向用户加载“加载”消息.HTML:Foo​使用Javascript:var foo = document.getElementById('foo');function tellViewerLoading() {// Tell the user that loading is occuring...

    我试图在

    javascript中调用耗时的函数之前向用户加载“加载”消息.

    HTML:

    Foo

    使用Javascript:

    var foo = document.getElementById('foo');

    function tellViewerLoading() {

    // Tell the user that loading is occuring.

    foo.innerHTML = 'loading...';

    }

    function someActionThatTakesALongTime() {

    // Do some action that takes a long time.

    var i = 0;

    while(i < 100000) {i++; console.log(i);};

    }

    function domUpdateDelayExperiment() {

    tellViewerLoading();

    someActionThatTakesALongTime();

    }

    domUpdateDelayExperiment();

    我想要发生的是在调用tellViewerLoading()之后立即更新DOM.

    相反,发生的事情是DOM似乎在someActionThatTakesALongTime()完成运行后更新.此时,显示加载消息是没用的.

    如何在调用tellViewerLoading()后告诉javascript立即更新DOM?

    展开全文
  • 故心故心故心故心小故冲啊 文章目录一、什么是...实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上 Ja

    故心故心故心故心小故冲啊



    在这里插入图片描述

    一、什么是虚拟DOM

    虚拟 DOM (Virtual DOM )这个概念相信大家都不陌生,从 React 到 Vue ,虚拟 DOM 为这两个框架都带来了跨平台的能力(React-Native 和 Weex)

    实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上

    在Javascript对象中,虚拟DOM 表现为一个 Object对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,不同框架对这三个属性的名命可能会有差别

    创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应

    在vue中同样使用到了虚拟DOM技术

    定义真实DOM

    <div id="app">
        <p class="p">节点内容</p>
        <h3>{{ foo }}</h3>
    </div>
    

    实例化vue

    const app = new Vue({
        el:"#app",
        data:{
            foo:"foo"
        }
    })
    

    观察render的render,我们能得到虚拟DOM

    (function anonymous() {
     with(this){return _c('div',{attrs:{"id":"app"}},[_c('p',{staticClass:"p"},
           [_v("节点内容")]),_v(" "),_c('h3',[_v(_s(foo))])])}})
    

    通过VNode,vue可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作, 经过diff算法得出一些需要修改的最小单位,再更新视图,减少了dom操作,提高了性能

    二、为什么需要虚拟DOM

    DOM是很慢的,其元素非常庞大,页面的性能问题,大部分都是由DOM操作引起的

    真实的DOM节点,哪怕一个最简单的div也包含着很多属性,可以打印出来直观感受一下:

    在这里插入图片描述
    由此可见,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验

    举个例子:

    你用传统的原生api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程

    当你在一次操作时,需要更新10个DOM节点,浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程

    而通过VNode,同样更新10个DOM节点,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,避免大量的无谓计算

    很多人认为虚拟 DOM 最大的优势是 diff 算法,减少 JavaScript 操作真实 DOM 的带来的性能消耗。虽然这一个虚拟 DOM 带来的一个优势,但并不是全部。虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI

    三、如何实现虚拟DOM

    首先可以看看vue中VNode的结构

    源码位置:src/core/vdom/vnode.js

    export default class VNode {
      tag: string | void;
      data: VNodeData | void;
      children: ?Array<VNode>;
      text: string | void;
      elm: Node | void;
      ns: string | void;
      context: Component | void; // rendered in this component's scope
      functionalContext: Component | void; // only for functional component root nodes
      key: string | number | void;
      componentOptions: VNodeComponentOptions | void;
      componentInstance: Component | void; // component instance
      parent: VNode | void; // component placeholder node
      raw: boolean; // contains raw HTML? (server only)
      isStatic: boolean; // hoisted static node
      isRootInsert: boolean; // necessary for enter transition check
      isComment: boolean; // empty comment placeholder?
      isCloned: boolean; // is a cloned node?
      isOnce: boolean; // is a v-once node?
    
      constructor (
        tag?: string,
        data?: VNodeData,
        children?: ?Array<VNode>,
        text?: string,
        elm?: Node,
        context?: Component,
        componentOptions?: VNodeComponentOptions
      ) {
        /*当前节点的标签名*/
        this.tag = tag
        /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
        this.data = data
        /*当前节点的子节点,是一个数组*/
        this.children = children
        /*当前节点的文本*/
        this.text = text
        /*当前虚拟节点对应的真实dom节点*/
        this.elm = elm
        /*当前节点的名字空间*/
        this.ns = undefined
        /*编译作用域*/
        this.context = context
        /*函数化组件作用域*/
        this.functionalContext = undefined
        /*节点的key属性,被当作节点的标志,用以优化*/
        this.key = data && data.key
        /*组件的option选项*/
        this.componentOptions = componentOptions
        /*当前节点对应的组件的实例*/
        this.componentInstance = undefined
        /*当前节点的父节点*/
        this.parent = undefined
        /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
        this.raw = false
        /*静态节点标志*/
        this.isStatic = false
        /*是否作为跟节点插入*/
        this.isRootInsert = true
        /*是否为注释节点*/
        this.isComment = false
        /*是否为克隆节点*/
        this.isCloned = false
        /*是否有v-once指令*/
        this.isOnce = false
      }
    
      // DEPRECATED: alias for componentInstance for backwards compat.
      /* istanbul ignore next https://github.com/answershuto/learnVue*/
      get child (): Component | void {
        return this.componentInstance
      }
    }
    

    这里对VNode进行稍微的说明:

    所有对象的 context 选项都指向了 Vue 实例
    elm 属性则指向了其相对应的真实 DOM 节点
    vue是通过createElement生成VNode

    源码位置:src/core/vdom/create-element.js

    export function createElement (
      context: Component,
      tag: any,
      data: any,
      children: any,
      normalizationType: any,
      alwaysNormalize: boolean
    ): VNode | Array<VNode> {
      if (Array.isArray(data) || isPrimitive(data)) {
        normalizationType = children
        children = data
        data = undefined
      }
      if (isTrue(alwaysNormalize)) {
        normalizationType = ALWAYS_NORMALIZE
      }
      return _createElement(context, tag, data, children, normalizationType)
    }
    

    上面可以看到createElement 方法实际上是对 _createElement 方法的封装,对参数的传入进行了判断

    export function _createElement(
        context: Component,
        tag?: string | Class<Component> | Function | Object,
        data?: VNodeData,
        children?: any,
        normalizationType?: number
    ): VNode | Array<VNode> {
        if (isDef(data) && isDef((data: any).__ob__)) {
            process.env.NODE_ENV !== 'production' && warn(
                `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
                'Always create fresh vnode data objects in each render!',
                context`
            )
            return createEmptyVNode()
        }
        // object syntax in v-bind
        if (isDef(data) && isDef(data.is)) {
            tag = data.is
        }
        if (!tag) {
            // in case of component :is set to falsy value
            return createEmptyVNode()
        }
        ... 
        // support single function children as default scoped slot
        if (Array.isArray(children) &&
            typeof children[0] === 'function'
        ) {
            data = data || {}
            data.scopedSlots = { default: children[0] }
            children.length = 0
        }
        if (normalizationType === ALWAYS_NORMALIZE) {
            children = normalizeChildren(children)
        } else if ( === SIMPLE_NORMALIZE) {
            children = simpleNormalizeChildren(children)
        }
     // 创建VNode
        ...
    }
    

    可以看到_createElement接收5个参数:

    context 表示 VNode 的上下文环境,是 Component 类型

    tag 表示标签,它可以是一个字符串,也可以是一个 Component

    data 表示 VNode 的数据,它是一个 VNodeData 类型

    children 表示当前 VNode的子节点,它是任意类型的

    normalizationType 表示子节点规范的类型,类型不同规范的方法也就不一样,主要是参考 render 函数是编译生成的还是用户手写的

    根据normalizationType 的类型,children会有不同的定义

    if (normalizationType === ALWAYS_NORMALIZE) {
        children = normalizeChildren(children)
    } else if ( === SIMPLE_NORMALIZE) {
        children = simpleNormalizeChildren(children)
    }
    

    simpleNormalizeChildren方法调用场景是 render 函数是编译生成的

    normalizeChildren方法调用场景分为下面两种:

    render 函数是用户手写的
    编译 slot、v-for 的时候会产生嵌套数组
    无论是simpleNormalizeChildren还是normalizeChildren都是对children进行规范(使children 变成了一个类型为 VNode 的 Array),这里就不展开说了

    规范化children的源码位置在:src/core/vdom/helpers/normalzie-children.js

    在规范化children后,就去创建VNode

    let vnode, ns
    // 对tag进行判断
    if (typeof tag === 'string') {
      let Ctor
      ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
      if (config.isReservedTag(tag)) {
        // 如果是内置的节点,则直接创建一个普通VNode
        vnode = new VNode(
          config.parsePlatformTagName(tag), data, children,
          undefined, undefined, context
        )
      } else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
        // component
        // 如果是component类型,则会通过createComponent创建VNode节点
        vnode = createComponent(Ctor, data, context, children, tag)
      } else {
        vnode = new VNode(
          tag, data, children,
          undefined, undefined, context
        )
      }
    } else {
      // direct component options / constructor
      vnode = createComponent(tag, data, context, children)
    }
    

    createComponent同样是创建VNode

    源码位置:src/core/vdom/create-component.js

    export function createComponent (
      Ctor: Class<Component> | Function | Object | void,
      data: ?VNodeData,
      context: Component,
      children: ?Array<VNode>,
      tag?: string
    ): VNode | Array<VNode> | void {
      if (isUndef(Ctor)) {
        return
      }
     // 构建子类构造函数 
      const baseCtor = context.$options._base
    
      // plain options object: turn it into a constructor
      if (isObject(Ctor)) {
        Ctor = baseCtor.extend(Ctor)
      }
    
      // if at this stage it's not a constructor or an async component factory,
      // reject.
      if (typeof Ctor !== 'function') {
        if (process.env.NODE_ENV !== 'production') {
          warn(`Invalid Component definition: ${String(Ctor)}`, context)
        }
        return
      }
    
      // async component
      let asyncFactory
      if (isUndef(Ctor.cid)) {
        asyncFactory = Ctor
        Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
        if (Ctor === undefined) {
          return createAsyncPlaceholder(
            asyncFactory,
            data,
            context,
            children,
            tag
          )
        }
      }
    
      data = data || {}
    
      // resolve constructor options in case global mixins are applied after
      // component constructor creation
      resolveConstructorOptions(Ctor)
    
      // transform component v-model data into props & events
      if (isDef(data.model)) {
        transformModel(Ctor.options, data)
      }
    
      // extract props
      const propsData = extractPropsFromVNodeData(data, Ctor, tag)
    
      // functional component
      if (isTrue(Ctor.options.functional)) {
        return createFunctionalComponent(Ctor, propsData, data, context, children)
      }
    
      // extract listeners, since these needs to be treated as
      // child component listeners instead of DOM listeners
      const listeners = data.on
      // replace with listeners with .native modifier
      // so it gets processed during parent component patch.
      data.on = data.nativeOn
    
      if (isTrue(Ctor.options.abstract)) {
        const slot = data.slot
        data = {}
        if (slot) {
          data.slot = slot
        }
      }
    
      // 安装组件钩子函数,把钩子函数合并到data.hook中
      installComponentHooks(data)
    
      //实例化一个VNode返回。组件的VNode是没有children的
      const name = Ctor.options.name || tag
      const vnode = new VNode(
        `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
        data, undefined, undefined, undefined, context,
        { Ctor, propsData, listeners, tag, children },
        asyncFactory
      )
      if (__WEEX__ && isRecyclableComponent(vnode)) {
        return renderRecyclableComponentTemplate(vnode)
      }
    
      return vnode
    }
    

    稍微提下createComponent生成VNode的三个关键流程:

    • 构造子类构造函数Ctor
    • installComponentHooks安装组件钩子函数
    • 实例化 vnode

    小结

    createElement 创建 VNode 的过程,每个 VNode 有 children,children 每个元素也是一个VNode,这样就形成了一个虚拟树结构,用于描述真实的DOM树结构

    参考文献

    https://ustbhuangyi.github.io/vue-analysis/v2/data-driven/create-element.html#children-%E7%9A%84%E8%A7%84%E8%8C%83%E5%8C%96
    https://juejin.cn/post/6876711874050818061

    展开全文
  • 什么是javascript dom?

    2021-06-14 05:17:17
    DOM就是文件对象模型。DOM将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。它会将web页面和JavaScript连接起来。DOM(document object model)文档对象模型,是一项W3C 标准,是针对HTML和XML的一...

    DOM就是文件对象模型。DOM将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。它会将web页面和JavaScript连接起来。

    5d5d006eac7bb998.jpg

    DOM(document object model)文档对象模型,是一项W3C 标准,是针对HTML和XML的一个API(应用程序接口)。它将web页面和JavaScript连接起来,允许程序和脚本动态地访问、更新文档的内容、结构和样式。

    它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。

    DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

    当网页被加载时,浏览器会创建页面的文档对象模型DOM(Document Object Model)。

    对象的 HTML DOM 树

    1566264415293785.jpg

    通过这个对象模型,JavaScript 获得创建动态 HTML 的所有力量:JavaScript 能改变页面中的所有 HTML 元素

    JavaScript 能改变页面中的所有 HTML 属性

    JavaScript 能改变页面中的所有 CSS 样式

    JavaScript 能删除已有的 HTML 元素和属性

    JavaScript 能添加新的 HTML 元素和属性

    JavaScript 能对页面中所有已有的 HTML 事件作出反应

    JavaScript 能在页面中创建新的 HTML 事件

    展开全文
  • ECMAScript规范指出:NodeLists是宿主对象,Array.prototype.slice不能保证宿主对象上使用方法可以正常工作。slice函数是否可以成功应用于宿主对象取决于实现。我建议您做一个简单的函数来遍历NodeList并将每个...

    ECMAScript规范指出:NodeLists是宿主对象,Array.prototype.slice不能保证在宿主对象上使用方法可以正常工作。

    slice函数是否可以成功应用于宿主对象取决于实现。

    我建议您做一个简单的函数来遍历NodeList并将每个现有元素添加到数组中:

    function toArray(obj) {

    var array = [];

    // iterate backwards ensuring that length is an UInt32

    for (var i = obj.length >>> 0; i--;) {

    array[i] = obj[i];

    }

    return array;

    }

    更新:

    正如其他答案所建议的那样,您现在可以在现代环境中使用传播语法或Array.from方法:

    const array = [ ...nodeList ] // or Array.from(nodeList)

    但是考虑一下,我想将NodeList转换为Array的最常见用例是对其进行迭代,现在该NodeList.prototype对象具有本forEach机方法,因此,如果您在现代环境中,则可以直接使用它,也可以使用满溢的

    展开全文
  • DOMElement只是设置对象的变换.var stage = new createjs.Stage("canvas");var html = document.createElement('div');html.id = 'ab';html.style.height = '50px';html.style.width = '100px';ht...
  • JavaScript操作DOM对象

    2021-01-22 16:21:01
    使用JavaScript操作DOM时分为三个方面:DOM Core(核心),HTML-DOM和CSS-DOM。通过这些标准,开发人员可以让网页真正的动起来,动态地添加,修改,删除数据,使用户和计算机的交互更加便捷,交互也更加丰富。 1.DOM ...
  • 虚拟DOM的作用和定义 什么是虚拟DOM 虚拟DOM就是普通的js对象。是一个用来描述真实dom结构的js对象,因为它不是真实的dom,所以才叫做虚拟dom。 虚拟dom的作用 我们都知道传统的dom数据发生变化的时候,我们都...
  • 当创建了一个网页 并把它加载到Web浏览器时,DOM幕后悄然而生。它把你编写 的网页文档转换为一个文档对象。 人类语言,“对象”这个词的含义往往不那么明确,它几乎可以用来 称呼任何一种东西。但程序...
  • 通常,当我们Angular中使用JavaScript技术时,我们几乎会忘记框架的特性。让我们去使用它们。 web开发中一个有趣的主题是DOM操作。Angular中,有很多方法可以操作DOM。 让我们使用它们而不是直接的JavaScript...
  • [vue] 如何实现一个虚拟DOM?说说你的思路 虚拟DOM本身是一个JavaScript对象模拟真实DOM ,用对象的属性去描述一个DOM节点,最终也只是一个真实DOM的映射 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很...
  • 在JavaScript中删除DOM节点的所有子元素我将如何在JavaScript中删除DOM节点的所有子元素?说我有以下(丑陋的)HTML:helloworld我抓住了我想要的节点:var myNode = document.getElementById("foo");我如何删除remove...
  • 之前我们已经把 JavaScript 基础部分全部学完了,基础部分一共分为了10篇,10篇的内容需要记住的东西还是挺多,所以需要你多编辑器敲一敲。应用实际的场景,纸上得来终觉浅,绝知此事要躬行。 WebApi ...
  • 本文为大家介绍了JavaScript中dom操作。1、理解DOMDOM(Document Object Model ,文档对象模型)一种独立于语言,用于操作xml,html文档的应用编程接口。从两个角度理解:对于JavaScript,为了能够使Jav...
  • 我正在使用Selenium WebDriver尝试将外部javascript文件插入DOM中,而不是将整个内容键入到executeScript。看起来好像已将节点正确放置到DOM中,但是随后它只是忽略了源代码,即,所述源js文件上的函数未运行。这...
  • 摘要:下文讲述原生态的js脚本通过DOM方法修改html元素的css样式的方法分享,如下所示:实现思路:使用DOM选择器的style属性即可对html元素进行css样式修改maomao365.com js修改Html标签样式的示例分享//绑定事件...
  • Javascript中关于监听DOM元素状态的方法使用 MutationObserver MutationObserver是针对DOM元素的观察器,观察它体内增加/减少子(爷孙)节点,或者子节点的属性等,可通过这一特性观察器增加相关的有利于实现...
  • JavaScript DOM

    千次阅读 2021-12-06 10:27:27
    DOM(Document Object Model):文档对象模型。 将 HTML 文档的各个组成部分,封装为对象。借助这些对象,可以对 HTML 文档进行增删改查的动态操作。
  • 想要使用JavaScript删除DOM节点的所有子元素,可以使用removeChild()或remove()方法删除所有子节点;另一个方法是设置DOM节点的innerHTML= " "属性,它是一个空字符串,生成相同的输出。image下面我们通过代码示例来...
  • [Java教程]JavaScript中DOM及相关操作02017-08-12 16:00:06一、什么是DOMJavaScript由ECMAScript、DOM和BOM三部分组成,其中DOM代表描述网页内容的方法和接口,即文档对象模型(Document Object Model)。...
  • (1)打印输出虚拟DOM是什么? <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>01_HelloWorld</title> </head> <body> <div id="test">&...
  • 01第一节:基本概念对于IT界的编程...Html DOM分配事件就拿#JavaScript#编程来说,它是一种脚本编程语言,与HTML深度合作,且提供了大量的HTML DOM操作,DOM功能非常强大,是未来HTML+JavaScript开发者的核心关注点...
  • 最近项目需求要开发百度地图相关的一个应用,需要从硬编码的html字符串提取自己想要的元素以及属性信息,由于js或者jq操作元素节点以及属性都是使用dom对象或者jq对象。下面介绍javascript中html字符串转化...
  • 我想克隆这个元素(并且所有应用的CSS和JS),将其序列化为一个字符串,我可以数据库保存以将来的请求添加到DOM。我知道jQuery有一些这样的方法(比如$ .css()来获取计算的样式),但是我该如何执行所有这些操作...
  • 通过style 属性获取样式有很大的局限性。 style 属性只能返回内嵌...这可不是使用样式的好办法——表现信息与结构混杂一起了。更好的 办法是用一个外部样式表去设置样式: p#example { color: grey; font: 12p
  • 文章目录HTML DOMHTML DOM概述...DOM是Document Object Model 文档对象(网页的标签)模型的缩写, DOM对象指的是一类对象的总称, 通过Html DOM, 可用JavaScript操作html文档的所有标签; 熟悉软件开发的人员可以将
  • 如果想改变一个文本节点的值,那就使用DOM提供的nodeValue 属 性,它用来得到(和设置)一个节点的值: node.nodeValue 但这里有个大家必须注意的细节:用nodeValue 属性获取 description 对象的值时,得到的并...
  • JavaScriptDom常用方法

    2021-08-11 19:08:22
    JavaScript常用Dom方法 getElementById() 返回带有指定ID 的元素。 getElementsByTagName() 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 getElementsByClassName() 返回包含带有指定类名的所有...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 442,314
精华内容 176,925
关键字:

在javascript中如何使用dom?

java 订阅