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 相关文章推荐
解决FireFox下[使用event很麻烦]的问题
Nov 26 Javascript
jquery $(this).attr $(this).val方法使用介绍
Oct 08 Javascript
js replace替换所有匹配的字符串
Feb 13 Javascript
javascript函数特点实例分析
May 14 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
Oct 16 Javascript
jquery实现的伪分页效果代码
Oct 29 Javascript
JS onkeypress兼容性写法详解
Apr 27 Javascript
AngularJS实现的根据数量与单价计算总价功能示例
Dec 26 Javascript
微信小程序实现登录注册tab切换效果
Dec 29 Javascript
JS实现图片拖拽交换效果
Nov 30 Javascript
Vue中消息横向滚动时setInterval清不掉的问题及解决方法
Aug 23 Javascript
关于vue表单提交防双/多击的例子
Oct 31 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保存信息到当前Session的方法
2015/03/16 PHP
js 实现打印网页中定义的部分内容的代码
2010/04/01 Javascript
让JavaScript拥有类似Lambda表达式编程能力的方法
2010/09/12 Javascript
jQuery bxCarousel实现图片滚动切换效果示例代码
2013/05/15 Javascript
JS模拟自动点击的简单实例
2013/08/08 Javascript
用JavaScript显示浏览器客户端信息的超相近教程
2015/06/18 Javascript
JavaScript代码性能优化总结(推荐)
2016/05/16 Javascript
Javascript 两种刷新方法以及区别和适用范围
2017/01/17 Javascript
JavaScript装饰器函数(Decorator)实例详解
2017/03/30 Javascript
jquery引入外部CDN 加载失败则引入本地jq库
2018/05/23 jQuery
使用vue-cli3新建一个项目并写好基本配置(推荐)
2019/04/24 Javascript
[01:05:36]VP vs TNC Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
python发送HTTP请求的方法小结
2015/07/08 Python
Python 多进程和数据传递的理解
2017/10/09 Python
Python爬虫番外篇之Cookie和Session详解
2017/12/27 Python
NumPy.npy与pandas DataFrame的实例讲解
2018/07/09 Python
Django csrf 验证问题的实现
2018/10/09 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
2019/04/26 Python
Python操作excel的方法总结(xlrd、xlwt、openpyxl)
2019/09/02 Python
Python实现密码薄文件读写操作
2019/12/16 Python
使用keras实现非线性回归(两种加激活函数的方式)
2020/07/05 Python
Numpy中的数组搜索中np.where方法详细介绍
2021/01/08 Python
美国生鲜及杂货电商:FreshDirect
2018/01/29 全球购物
高性能装备提升营地:Kammok
2019/02/27 全球购物
英国折扣高尔夫商店:Discount Golf Store
2019/11/19 全球购物
浙大网新C/C++面试解惑
2015/05/27 面试题
科室工作个人总结的自我评价
2013/10/29 职场文书
药学专业大学生个人的自我评价
2013/11/04 职场文书
小学教师自我剖析材料
2014/09/29 职场文书
防灾减灾宣传标语
2014/10/07 职场文书
前台文员岗位职责
2015/02/04 职场文书
2015年党务工作者个人工作总结
2015/10/22 职场文书
李白经典诗之一:全文无一“月”字,却句句有月
2019/07/12 职场文书
如何判断微信付款码和支付宝付款码
2021/04/01 PHP
html中显示特殊符号(附带特殊字符对应表)
2021/06/21 HTML / CSS
TaiShan 200服务器安装Ubuntu 18.04的图文教程
2022/06/28 Servers