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 相关文章推荐
创建一个复制UBB软件信息的链接或按钮的js代码
Jan 06 Javascript
jquery事件机制扩展插件 jquery鼠标右键事件。
Dec 26 Javascript
JavaScript instanceof 的使用方法示例介绍
Oct 23 Javascript
深入分析Cookie的安全性问题
Mar 01 Javascript
JavaScript实现同时调用多个函数的方法
Nov 09 Javascript
利用jQuery设计一个简单的web音乐播放器的实例分享
Mar 08 Javascript
jQuery Ajax 实例代码 ($.ajax、$.post、$.get)
Apr 29 Javascript
详解Node.js模块间共享数据库连接的方法
May 24 Javascript
详解Sea.js中Module.exports和exports的区别
Feb 12 Javascript
JS控件bootstrap suggest plugin使用方法详解
Mar 25 Javascript
微信小程序promsie.all和promise顺序执行
Oct 27 Javascript
如何通过setTimeout理解JS运行机制详解
Mar 23 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
Yii2中关联查询简单用法示例
2016/08/10 PHP
CI框架表单验证实例详解
2016/11/21 PHP
Laravel 框架基于自带的用户系统实现登录注册及错误处理功能分析
2020/04/14 PHP
聊聊 PHP 8 新特性 Attributes
2020/08/19 PHP
javascript 写类方式之二
2009/07/05 Javascript
js动态设置鼠标事件示例代码
2013/10/30 Javascript
用js读、写、删除Cookie代码分享及详细注释说明
2014/06/05 Javascript
jquery和css3实现的炫酷时尚的菜单导航
2014/09/01 Javascript
JavaScript学习笔记之数组的增、删、改、查
2016/03/23 Javascript
jQuery使用cookie与json简单实现购物车功能
2016/04/15 Javascript
JS实现touch 点击滑动轮播实例代码
2017/01/19 Javascript
Javascript仿京东放大镜的效果
2017/03/01 Javascript
angular-cli修改端口号【angular2】
2017/04/19 Javascript
webpack踩坑之路图片的路径与打包
2017/09/05 Javascript
vue 动态修改a标签的样式的方法
2018/01/18 Javascript
解决Layui选择全部,换页checkbox复选框重新勾选的问题方法
2018/08/14 Javascript
[04:30]显微镜下的DOTA2第五期——拉比克
2013/09/26 DOTA
详谈Pandas中iloc和loc以及ix的区别
2018/06/08 Python
[原创]Python入门教程1. 基本运算【四则运算、变量、math模块等】
2018/10/28 Python
Python将一个Excel拆分为多个Excel
2018/11/07 Python
在unittest中使用 logging 模块记录测试数据的方法
2018/11/30 Python
python实现windows壁纸定期更换功能
2019/01/21 Python
python垃圾回收机制(GC)原理解析
2019/12/30 Python
使用Python FastAPI构建Web服务的实现
2020/06/08 Python
python-地图可视化组件folium的操作
2020/12/14 Python
很酷的小工具和电子产品商城:GearBest
2016/11/19 全球购物
销售找工作求职信
2013/12/20 职场文书
党员的自我评价范文
2014/01/02 职场文书
个性发展自我评价
2014/02/11 职场文书
优秀团员自我评价范文
2014/04/23 职场文书
电钳工人个人求职信
2014/05/10 职场文书
英语系毕业生求职信
2014/07/13 职场文书
孝老爱亲事迹材料
2014/12/24 职场文书
2015年售票员工作总结
2015/04/29 职场文书
心术观后感
2015/06/11 职场文书
Java 在线考试云平台的实现
2021/11/23 Java/Android