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显示随机图像或引用
Apr 21 Javascript
JavaScript 学习笔记(六)
Dec 31 Javascript
jQuery图片预加载 等比缩放实现代码
Oct 04 Javascript
jQuery控制图片的hover效果(smartRollover.js)
Mar 18 Javascript
javascript先序遍历DOM树的方法
Feb 27 Javascript
详解JavaScript的另类写法
Apr 11 Javascript
JS获取子窗口中返回的数据实现方法
May 28 Javascript
JS实现简单抖动效果
Jun 01 Javascript
详解webpack+vue-cli项目打包技巧
Jun 17 Javascript
vue中改变选中当前项的显示隐藏或者状态的实现方法
Feb 08 Javascript
详解Vue项目中出现Loading chunk {n} failed问题的解决方法
Sep 14 Javascript
浅谈JavaScript中this的指向问题
Jul 28 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命令空间namespace及use的用法小结
2017/11/27 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
新手常遇到的一些jquery问题整理
2010/08/16 Javascript
根据表格中的某一列进行排序的javascript代码
2013/11/29 Javascript
鼠标移到div,浮层显示明细,弹出层与div的上边距左边距重合(示例代码)
2013/12/14 Javascript
flash遮住div问题的正确解决方法
2014/02/27 Javascript
js语法学习之判断一个对象是否为数组
2014/05/13 Javascript
Jquery通过JSON字符串创建JSON对象
2014/08/24 Javascript
js实现图片粘贴上传到服务器并展示的实例
2017/11/08 Javascript
浅析Angular 实现一个repeat指令的方法
2019/07/21 Javascript
vue路由跳转传递参数的方式总结
2020/05/10 Javascript
Python发送email的3种方法
2015/04/28 Python
Python编程中对super函数的正确理解和用法解析
2016/07/02 Python
python3编码问题汇总
2016/09/06 Python
值得收藏的10道python 面试题
2019/04/15 Python
为什么从Python 3.6开始字典有序并效率更高
2019/07/15 Python
简单了解Django ContentType内置组件
2019/07/23 Python
解决使用export_graphviz可视化树报错的问题
2019/08/09 Python
python实现IOU计算案例
2020/04/12 Python
如何使用Cython对python代码进行加密
2020/07/08 Python
Django3中的自定义用户模型实例详解
2020/08/23 Python
如何在scrapy中捕获并处理各种异常
2020/09/28 Python
如何用border-image实现文字气泡边框的示例代码
2020/01/21 HTML / CSS
CSS3 实现穿梭星空动画
2020/11/13 HTML / CSS
Herve Leger官网:标志性绷带连衣裙等
2018/12/26 全球购物
经典c++面试题六
2012/01/18 面试题
毕业自我评价范文
2013/11/17 职场文书
会展中心部门工作职责
2013/11/27 职场文书
新书吧创业计划书
2014/01/31 职场文书
班主任经验交流会主持词
2014/04/01 职场文书
竞聘自述材料
2014/08/25 职场文书
交通工程专业推荐信
2014/09/06 职场文书
2014年党的群众路线学习心得体会
2014/11/05 职场文书
2015年教研工作总结
2015/05/23 职场文书
pytorch 实现变分自动编码器的操作
2021/05/24 Python
CentOS7安装MySQL8的超级详细教程(无坑!)
2022/06/10 Servers