js技巧之十几行的代码实现vue.watch代码


Posted in Javascript onJune 09, 2018

getter和setter

getter 是一种获得属性值的方法,setter是一种设置属性值的方法。
属性被赋值 a = 1的时候, a 的原型内的setter就会被触发;
而 console.log(a) 的时候,a 的原型内的getter就会被触发。

实现getter和setter

我们不能直接给变量的setter和getter 绑定事件函数,为了实现绑定我们要借助Object对象来构造带有setter和getter的属性。

这里有前辈总结的 几种实现getter和setter的方法,而且他还总结了一些Object.prototype内控制属性枚举的特性的隐式属性。

我这里选用了比较好构造的一种 Object.defineProperty

概要
Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。
语法
Object.defineProperty(obj, prop, descriptor)
参数
obj
需要定义属性的对象。
prop
需被定义或修改的属性名。
descriptor
需被定义或修改的属性的描述符。

  1. 第一个参数,被构造的属性的this指向的对象
  2. 第二个参数,被构造的属性名
  3. 第三个参数,构造的规则(上面的文字链接最后面有介绍)
(function () {
  var o = { a : 1}//声明一个对象,包含一个 a 属性,值为1
  Object.defineProperty(o,"b",{
    get: function () {
      return this.a;
    },
    set : function (val) {
      this.a = val;
    },
    configurable : true
  });

  console.log(o.b);//==> 1
  o.b = 2;
  console.log(o.b);//==> 2
})();

configurable是指 "b" 是否可以被再配置,默认是false。false的话
Object.defineProperty(o,"a",{set : function(val){}} );

再修改时会不起作用或者报错,一般默认false。

构造我们的vue.watch

目标实现,以下是我们想要的达到的效果

import watcher from './watcher.js';
let wm = new watcher({
  data:{
    a: 0 
  },
  watch:{
    a(newVal,oldVal){
      console.log('newVal:'+newVal);
      console.log('oldVal:'+oldVal);
    }
  }
})
vm.a = 1 
// newVal:1
// oldVal:0

创建构造对象

class watcher{
  constructor(opts){
    this.$data = opts.data;
    for(let key in opts.data){
      this.setData(key,opts.data[key])
    }
  }

  setData(_key,_val){
    Object.defineProperty(this,_key,{
      get: function () {
        return this.$data[_key];
      },
      set : function (val) {
        const oldVal = this.$data[_key];
        if(oldVal === val)return val;
        this.$data[_key] = val;
        return val;
      },
    });
  }
}

export default watcher;

添加 watch事件触发

/**
 * @desc 属性改变监听,属性被set时出发watch的方法,类似vue的watch
 * @author Jason
 * @date 2018-04-27
 * @constructor 
 * @param {object} opts - 构造参数. @default {data:{},watch:{}};
 * @argument {object} data - 要绑定的属性
 * @argument {object} watch - 要监听的属性的回调 
 * watch @callback (newVal,oldVal) - 新值与旧值 
 */
class watcher{
  constructor(opts){
    this.$data = this.getBaseType(opts.data) === 'Object' ? opts.data : {};
    this.$watch = this.getBaseType(opts.watch) === 'Object' ? opts.watch : {};
    for(let key in opts.data){
      this.setData(key)
    }
  }

  getBaseType(target) {
    const typeStr = Object.prototype.toString.apply(target);
  
    return typeStr.slice(8, -1);
  }

  setData(_key){
    Object.defineProperty(this,_key,{
      get: function () {
        return this.$data[_key];
      },
      set : function (val) {
        const oldVal = this.$data[_key];
        if(oldVal === val)return val;
        this.$data[_key] = val;
        this.$watch[_key] && typeof this.$watch[_key] === 'function' && (
          this.$watch[_key].call(this,val,oldVal)
        );
        return val;
      },
    });
  }
}

export default watcher;
  • 为了函数内部的健壮性,getBaseType是用来做类型校验的。
  • Object.defineProperty(this),this把上下文指向当前对象。
  • this.$watch[_key].call(this,val,oldVal),把监听事件的上下文页绑定到当前对象,方便在watch内通过this获取对象内的值,如下
let wm = new watcher({
  data:{
    a: 0,
    b: 'hello'
  },
  watch:{
    a(newVal,oldVal){
      console.log(this.b);
    }
  }
})

总结

有人可能会问为什么不直接用vue呢。你也知道vue是一个工程级别的框架,做比较大的项目当然是用vue,react;但是单单做一个展示性的官网或者做个移动端的H5宣传页也用上vue吗?那当然是没有必要的。
用上这一个watcher类,可以让你页面的状态控制有条理、有迹可循。
比如几个按钮联动一个或几个视图的改变和动效的时候,你就不用在每个按钮的click时都触发一下修改

btn1.onclick=function(){
  var a = 'haha';
  document.getElementById('id').innerHTML = a;
 }
 btn2.onclick=function(){
  var a = 'xixi';
  document.getElementById('id').innerHTML = a;
 }
let wm = new watcher({
  data:{
    a: "",
  },
  watch:{
    a(newVal,oldVal){
      document.getElementById('id').innerHTML = newVal;
    }
  }
})

btn1.onclick=function(){
  wm.a = 'haha';
 }
 btn2.onclick=function(){
  wm.a = 'xixi';
 }

但是如果你的视图不被2个以上动作联动的话,也未必会用上。

Javascript 相关文章推荐
JavaScript获得选中文本内容的方法
Dec 02 Javascript
jQuery Flash/MP3/Video多媒体插件
Jan 18 Javascript
JavaScript游戏之是男人就下100层代码打包
Nov 08 Javascript
Javascript闭包用法实例分析
Jan 23 Javascript
jQuery简单tab切换效果实现方法
Apr 08 Javascript
信息页文内画中画广告js实现代码(文中加载广告方式)
Jan 03 Javascript
Bootstrap基本布局实现方法详解
Nov 25 Javascript
基于javascript实现按圆形排列DIV元素(一)
Dec 02 Javascript
ES6学习笔记之正则表达式和字符串正则方法分析
Apr 25 Javascript
layer设置maxWidth及maxHeight解决方案
Jul 26 Javascript
vue实现移动端返回顶部
Oct 12 Javascript
关于uniApp editor微信滑动问题
Jan 15 Javascript
浅谈JS对象添加getter与setter的5种方法
Jun 09 #Javascript
让你5分钟掌握9个JavaScript小技巧
Jun 09 #Javascript
jQuery基于闭包实现的显示与隐藏div功能示例
Jun 09 #jQuery
JS实现区分中英文并统计字符个数的方法示例
Jun 09 #Javascript
详解angular脏检查原理及伪代码实现
Jun 08 #Javascript
解析vue路由异步组件和懒加载案例
Jun 08 #Javascript
node中modules.exports与exports导出的区别
Jun 08 #Javascript
You might like
PHP实现打包zip并下载功能
2018/06/12 PHP
PHP+MySql实现一个简单的留言板
2020/07/19 PHP
基于jQuery的合并表格中相同文本的相邻单元格的代码
2011/04/06 Javascript
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
javascript实现跳转菜单的具体方法
2013/07/05 Javascript
javascript中的toFixed固定小数位数 简单实例分享
2013/07/12 Javascript
解决JQeury显示内容没有边距内容紧挨着浏览器边线
2013/12/20 Javascript
以jQuery中$.Deferred对象为例讲解promise对象是如何处理异步问题
2015/11/13 Javascript
javascript下拉列表中显示树形菜单的实现方法
2015/11/17 Javascript
AngularJS中如何使用echart插件示例详解
2016/10/26 Javascript
浅谈jQuery中的$.extend方法来扩展JSON对象
2017/02/12 Javascript
bootstrap表单示例代码分享
2017/05/18 Javascript
JS实现简单抖动效果
2017/06/01 Javascript
vue mounted组件的使用
2018/06/18 Javascript
[05:56]第十六期——新进3大C之小兔基
2014/06/24 DOTA
[40:05]LGD vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
Python3中常用的处理时间和实现定时任务的方法的介绍
2015/04/07 Python
python实现彩票系统
2020/06/28 Python
Python3 导入上级目录中的模块实例
2019/02/16 Python
详解Python用户登录接口的方法
2019/04/17 Python
pygame实现俄罗斯方块游戏(对战篇1)
2019/10/29 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
tensorflow-gpu安装的常见问题及解决方案
2020/01/20 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
使用matplotlib动态刷新指定曲线实例
2020/04/23 Python
python如何使用代码运行助手
2020/07/03 Python
浅析图片上传及canvas压缩的流程
2020/06/10 HTML / CSS
财务会计专业推荐信
2013/11/30 职场文书
自我评价怎么写正确呢?
2013/12/02 职场文书
总经理文秘岗位职责
2014/02/03 职场文书
小学庆六一活动方案
2014/02/28 职场文书
医院信息公开实施方案
2014/05/09 职场文书
文明礼仪标语
2014/06/13 职场文书
2015新员工试用期工作总结
2014/12/12 职场文书
Python 内置函数速查表一览
2021/06/02 Python
Java设计模式之享元模式示例详解
2022/03/03 Java/Android