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 相关文章推荐
js自带函数备忘 数组
Dec 29 Javascript
jQuery 处理网页内容的实现代码
Feb 15 Javascript
js 显示base64编码的二进制流网页图片
Apr 04 Javascript
JS版元素周期表实现方法
Aug 05 Javascript
谷歌showModalDialog()方法不兼容出现对话窗口的解决办法
Feb 15 Javascript
js图片轮播手动切换特效
Jan 12 Javascript
Javacript中自定义的map.js  的方法
Nov 26 Javascript
vue自定义指令directive实例详解
Jan 17 Javascript
JavaScript实现表单注册、表单验证、运算符功能
Oct 15 Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
Dec 03 Javascript
Vue使用axios出现options请求方法
May 30 Javascript
Vue实现简单购物车功能
Dec 13 Vue.js
浅谈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 反射(Reflection)使用实例
2015/05/12 PHP
Symfony2框架学习笔记之HTTP Cache用法详解
2016/03/18 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
js 中{},[]中括号,大括号使用详解
2011/05/12 Javascript
jquery focus(fn),blur(fn)方法实例代码
2011/12/16 Javascript
JS实现程序暂停与继续功能代码解读
2013/10/10 Javascript
Js实现手机发送验证码时按钮延迟操作
2014/06/20 Javascript
JS简单去除数组中重复项的方法
2016/09/13 Javascript
Angular的$http与$location
2016/12/26 Javascript
Vue.Draggable实现拖拽效果
2020/07/29 Javascript
JS中offset和匀速动画详解
2018/02/06 Javascript
webpack里使用jquery.mCustomScrollbar插件的方法
2018/05/30 jQuery
解决vue接口数据赋值给data没有反应的问题
2018/08/27 Javascript
vue组件(全局,局部,动态加载组件)
2018/09/02 Javascript
vue实现打印功能的两种方法
2018/09/07 Javascript
webpack + vue 打包生成公共配置文件(域名) 方便动态修改
2019/08/29 Javascript
[01:10]DOTA2次级职业联赛 - Fly战队宣传片
2014/12/01 DOTA
Python中条件选择和循环语句使用方法介绍
2013/03/13 Python
Python中使用PIPE操作Linux管道
2015/02/04 Python
Python实现计算文件夹下.h和.cpp文件的总行数
2015/04/23 Python
python中的break、continue、exit()、pass全面解析
2017/08/05 Python
Python数据集切分实例
2018/12/08 Python
PyQt编程之如何在屏幕中央显示窗体的实例
2019/06/18 Python
详解python中的生成器、迭代器、闭包、装饰器
2019/08/22 Python
python类中super() 的使用解析
2019/12/19 Python
Python实现加密的RAR文件解压的方法(密码已知)
2020/09/11 Python
python与js主要区别点总结
2020/09/13 Python
python实现按日期归档文件
2021/01/30 Python
实习鉴定评语
2014/01/19 职场文书
合作经营协议书范本
2014/04/17 职场文书
简洁的英文求职信范文
2014/05/03 职场文书
普通党员个人对照检查材料
2014/09/18 职场文书
2015年电教工作总结
2015/05/26 职场文书
开业典礼致辞
2015/07/29 职场文书
朋友聚会祝酒词
2015/08/10 职场文书
某某店铺的开业庆典主持词范本
2019/11/25 职场文书