代码改变世界

随笔分类 -  javascript

vue自定义指令(Directive中的clickoutside.js)的理解

2017-06-04 17:50 by 龙恩0707, 13927 阅读, 收藏, 编辑
摘要: vue自定义指令(Directive中的clickoutside.js)的理解 阅读全文

ztree树形菜单demo

2017-05-30 17:33 by 龙恩0707, 3845 阅读, 收藏, 编辑
摘要: ztree树形菜单demo 阅读全文

vue全局API

2017-05-30 11:14 by 龙恩0707, 699 阅读, 收藏, 编辑
摘要: vue全局API 阅读全文

vue指令相关的

2017-05-29 15:41 by 龙恩0707, 586 阅读, 收藏, 编辑
摘要: vue指令相关的 阅读全文

理解 Mutation Observer

2017-05-13 19:07 by 龙恩0707, 3813 阅读, 收藏, 编辑

阅读目录

1.理解 Mutation Observer

Mutation Observer(变动观察器) 是监听DOM变动的接口,DOM发生任何变动,Mutation Observer会得到通知。
它与事件类似,但有所不同,事件是同步的,也就是说DOM发生变动,事件立刻会处理,而Mutation Observer则是异步,它不会立即处理,而是等页面上所有的DOM完成后,执行一次,如果页面上要操作100次DOM的话,那么事件会监听100次DOM,而Mutation Observer只会执行一次,等所有的DOM操作完成后,执行。

它的特点是:
1. 等待所有脚本任务完成后,才会执行,即采用异步方式。
2. DOM的变动记录封装成一个数组进行处理,而不是一条条的个别处理DOM变动。
3. 还可以观测发生在DOM的所有类型变动,也可以观测某一类变动。

浏览器支持如下:

下面的代码是检测浏览器是否支持该属性。如下代码:

var MutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver;
// 监测浏览器是否支持
var observeMutationSupport = !!MutationObserver;

MutationObserver 构造函数

使用 MutationObserver 构造函数,新建一个观察器实例,同时指定该实例的回调函数。如下:
var observer = new MutationObserver(callback);

观察器回调函数会在每次DOM发生变动后调用,接受2个参数,第一个是变动数组,第二个是观察器实例。

Mutation Observer 实例的方法
1. observe() 该方法所要观察的DOM节点,以及所要观察的特定变动。
该方法接受2个参数,第一个参数是所要观察的DOM元素,第二个所要观察的变动类型。
调用方式:observer.observe(dom, options);
那么类型有如下:
childList: 子节点的变动。
attributes: 属性的变动。
characterData: 节点内容或节点文本的变动。
subtree 所有后代节点的变动。

需要观察哪一种变动类型,需要在options对象中指定为true即可;但是如果设置subtree的变动,必须同时指定childList, attributes 和 characterData 中的一种或多种。

1. 监测childList的变动;

如下demo代码:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        console.log(mutations);
        console.log(instance);
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });

     Observer.observe(list, {
        childList: true,
        subtree: true
     });
     list.appendChild(document.createElement('div'));
     list.appendChild(document.createTextNode('foo'));
     list.removeChild(list.childNodes[0]);
     list.childNodes[0].appendChild(document.createElement('div'));
  </script>
</html>

控制台查看效果

如上代码 在控制台上打印信息如下,我们打印第一个回调参数 mutations 后,截图如下:

2. 监测characterData的变动

代码如下:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });
    Observer.observe(list, {
      childList:true,
      characterData:true,
      subtree:true
    });   
    list.childNodes[0].data = "cha";
  </script>
</html>

控制台查看效果

3. 监测属性的变动;
代码如下:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });
    Observer.observe(list, {
      attributes: true
    });   
    // 设置节点的属性  会触发回调函数
    list.setAttribute('data-value', '111');

    // 重新设置属性 会触发回调
    list.setAttribute('data-value', '2222');

    // 删除属性 也会触发回调
    list.removeAttribute('data-value');
  </script>
</html>

控制台查看效果

如下图所示:

除了基本的变动类型之外,options对象还可以设定以下属性
attributeOldValue: {boolean} 表示观察attributes变动时,是否需要记录变动前的属性值。
characterDataOldValue: {boolean} 表示观察characterData变动时,是否需要记录变动前的值。
attributeFilter {Array} 表示需要观察的特定属性 比如 ['class', 'src']

1. attributeOldValue 属性变动前,是否需要记录变动之前的值; 代码如下:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });
    Observer.observe(list, {
      attributes: true,
      attributeOldValue: true  
    });   
    // 设置节点的属性  会触发回调函数
    list.setAttribute('data-value', '111');

    // 删除属性 
    list.setAttribute('data-value', '2222');
  </script>
</html>

控制台查看效果

如上截图的oldValue 就是变动之前的值

2. characterData变动时,是否需要记录变动前的值。
如下代码:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });
    Observer.observe(list, {
      childList:true,
      characterData:true,
      subtree:true,
      characterDataOldValue: true
    });   
    // 设置数据 触发回调
    list.childNodes[0].data = "aaa";

    // 重新设置数据 重新触发回调
    list.childNodes[0].data = "bbbb";
  </script>
</html>

控制台查看效果

第一次设置数据,记录变动前的数据如下:

第二次设置数据,记录变动前的回调如下:

可以看到oldValue 的变动值;

attributeFilter {Array} 表示需要观察的特定属性 比如 ['class', 'src'];代码如下:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
        });
     });
    Observer.observe(list, {
      attributes: true,
      attributeFilter: ['data-value']
    });   
    // 第一次设置属性 data-key 不会触发的,因为data-value 不存在
    list.setAttribute('data-key', 1);

    // 第二次会触发
    list.setAttribute('data-value', 1);
  </script>
</html>

控制台查看效果

下面我们做一个简单的demo编辑器,首先给父级元素 ol 设置 contenteditable 让容器可编辑,然后构造一个observer 监听子元素的变化,每次回车的时候,控制台输出它的内容;如下代码:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol contenteditable oninput="" style='border: 1px solid red'>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          console.log(mutation);
          if(mutation.type === 'childList') {
            var list_values = [].slice.call(list.children).map(function(node) {
              return node.innerHTML;
            }).filter(function(s) {
              if(s === '<br>') {
                return false;
              } else {
                return true;
              }
            });
            console.log(list_values);
          }
        });
     });
    Observer.observe(list, {
      childList: true
    });   
    
  </script>
</html>

控制台查看效果

现在我们继续可以做一个类似于 input和textarea中的 valueChange的事件一样的,监听值变化,之前的值和之后的值,如下代码:

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='demo'>
      <ol contenteditable oninput="" style='border: 1px solid red'>
        <li>111111</li>
      </ol>
    </div>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var list = document.querySelector('ol');

     var Observer = new MutationObserver(function(mutations, instance){
        mutations.forEach(function(mutation){
          var enter = {
            mutation: mutation,
            el: mutation.target,
            newValue: mutation.target.textContent,
            oldValue: mutation.oldValue
          };
          console.log(enter);
        })
     });
    Observer.observe(list, {
      childList: true,
      attributes: true,
      characterData: true,
      subtree: true,
      characterDataOldValue: true,
    });   
    
  </script>
</html>

控制台查看效果

注意: 对input 和 textarea 不起作用的。

编辑器统计字数的demo

<!DOCTYPE html>
<html>
  <head>
    <title>演示Vue</title>
    <style>
      
    </style>
  </head>
  <body>
    <div id='editor' contenteditable style="width: 240px; height: 80px; border: 1px solid red;"></div>
    <p id="textInput">还可以输入100字</p>
  </body>

  <script type="text/javascript">
     var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     var editor = document.querySelector('#editor');
     var textInput = document.querySelector('#textInput');
     var observer = new MutationObserver(function(mutations){
        mutations.forEach(function(mutation) {
          if(mutation.type === 'characterData') {
            var newValue = mutation.target.textContent;
            textInput.innerHTML = "还可以输入" +  (1000 - newValue.length+"");
          }
        });
     });
    observer.observe(editor, {
      childList: true,
      attributes: true,
      characterData: true,
      subtree: true,
      characterDataOldValue: true,
    });   
    
  </script>
</html>

控制台查看效果

VUE2 第六天学习--- vue单文件项目构建

2017-05-09 23:13 by 龙恩0707, 4940 阅读, 收藏, 编辑
摘要: VUE2 第六天学习--- vue单文件项目构建 阅读全文

VUE2第五天学习---自定义指令

2017-05-09 00:17 by 龙恩0707, 1509 阅读, 收藏, 编辑
摘要: VUE2第五天学习---自定义指令 阅读全文

VUE2 第五天学习--过渡效果

2017-05-08 21:34 by 龙恩0707, 3999 阅读, 收藏, 编辑
摘要: VUE2 第五天学习--过渡效果 阅读全文

Vue2 第四天学习(Vue的生命周期)

2017-05-06 01:53 by 龙恩0707, 2323 阅读, 收藏, 编辑
摘要: Vue2 第四天学习(Vue的生命周期) 阅读全文

Vue2---父子组件之间的访问

2017-05-04 00:41 by 龙恩0707, 3106 阅读, 收藏, 编辑
摘要: Vue2---父子组件之间的访问 阅读全文

Vue2 第三天学习

2017-05-03 23:01 by 龙恩0707, 648 阅读, 收藏, 编辑
摘要: Vue2 第三天学习 阅读全文

Vue2 第二天学习

2017-05-02 23:25 by 龙恩0707, 1351 阅读, 收藏, 编辑
摘要: Vue2学习第二天 阅读全文

jQuery1.9.1源码分析--数据缓存Data模块

2016-05-19 00:52 by 龙恩0707, 1675 阅读, 收藏, 编辑
摘要: jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(elem, name, data)源码分析 internalRemoveData方法源码分析 internalData方法的源码分析 jQuery.fn.extend({data: function( key, value ) {}})源码分析 jQuery.extend({removeData: function( elem, name ) {}})源码分析 jQuery.cleanData(elems)源码分析 jQuery.hasData(elem)源码分析 阅读全文

浅谈javascript函数节流

2016-03-13 17:24 by 龙恩0707, 2064 阅读, 收藏, 编辑
摘要: 浅谈javascript函数节流 阅读全文

移动端事件介绍

2016-02-21 11:04 by 龙恩0707, 2633 阅读, 收藏, 编辑
摘要: 移动端事件介绍 阅读全文

Javascript设计模式详解

2016-02-18 15:41 by 龙恩0707, 89313 阅读, 收藏, 编辑
摘要: 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javascript中的策略模式 九:Javascript中理解发布--订阅模式 十:理解中介者模式 阅读全文

【干货理解】理解javascript中实现MVC的原理

2016-01-24 22:27 by 龙恩0707, 8873 阅读, 收藏, 编辑
摘要: MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法。模型有对数据直接访问的权利。模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作. 视图:视图层最主要的是监听模型层上的数据改变,并且实时的更新html页面。当然也包括一些事件的注册或者ajax请求操作(发布事件),都是放在视图层来完成。 控制器:控制器接收用户的操作,最主要是订阅视图层的事件,然后调用模型或视图去完成用户的操作;比如:当页面上触发一个事件,控制器不输出任何东西及对页面做任何处理; 它只是接收请求并决定调用模型中的那个方法去处理请求, 然后再确定调用那个视图中的方法来显示返回的数据。 阅读全文

[干货]数据交互与本地存储

2016-01-16 15:02 by 龙恩0707, 3115 阅读, 收藏, 编辑
摘要: 一:Iframe父页面与子页面之间的调用 二:理解JSONP跨域技术的基本原理 三:iframe之间通信问题 四:iframe高度自适应的问题。 五:本地存储cookie,sessionStorage, localStorage比较及使用 六:window.name 实现跨域数据传输。 七:使用HTML5中postMessage 实现ajax中的POST跨域问题 阅读全文

深入理解Javascript面向对象编程

2015-12-22 22:49 by 龙恩0707, 25706 阅读, 收藏, 编辑
摘要: 一:理解构造函数原型(prototype)机制 二:理解原型域链的概念 三:理解原型继承机制 四:理解使用类继承(继承的更好的方案) 五:建议使用封装类实现继承 六:理解使用复制继承 阅读全文

javascript数组的知识点讲解

2015-12-17 00:23 by 龙恩0707, 5337 阅读, 收藏, 编辑
摘要: javascript数组的知识点讲解 阅读全文
点击右上角即可分享
微信分享提示