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数组的扩展实现代码集合
Jun 01 Javascript
图片自动缩小 点击放大
Jul 07 Javascript
说说掌握JavaScript语言的思想前提想学习js的朋友可以看看
Apr 01 Javascript
JavaScript检查某个function是否是原生代码的方法
Aug 20 Javascript
jQuery四种选择器使用及示例
Jun 05 Javascript
Javascript实现倒计时时差效果
May 18 Javascript
浅谈手写node可读流之流动模式
Jun 01 Javascript
vue中利用Promise封装jsonp并调取数据
Jun 18 Javascript
《javascript设计模式》学习笔记五:Javascript面向对象程序设计工厂模式实例分析
Apr 08 Javascript
react PropTypes校验传递的值操作示例
Apr 28 Javascript
Vue组件通信$attrs、$listeners实现原理解析
Sep 03 Javascript
如何使用JavaScript策略模式校验表单
Apr 29 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 修改zen-cart下单和付款流程以防止漏单
2010/03/08 PHP
php读取javascript设置的cookies的代码
2010/04/12 PHP
php&mysql 日期操作小记
2012/02/27 PHP
php实现留言板功能(代码详解)
2017/03/28 PHP
php字符串过滤strip_tags()函数用法实例分析
2019/06/24 PHP
判断iframe是否加载完成的完美方法
2010/01/07 Javascript
jquery实现简单的自动播放幻灯片效果
2015/06/13 Javascript
javascript实现tab切换的四种方法
2015/11/05 Javascript
浅析在javascript中创建对象的各种模式
2016/05/06 Javascript
Jquery插件仿百度搜索关键字自动匹配功能
2016/05/11 Javascript
Bootstrap Table表格一直加载(load)不了数据的快速解决方法
2016/09/17 Javascript
JS对大量数据进行多重过滤的方法
2016/11/04 Javascript
javascript中call,apply,bind函数用法示例
2016/12/19 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
推荐三款日期选择插件(My97DatePicker、jquery.datepicker、Mobiscroll)
2017/04/21 jQuery
Angular2监听页面大小变化的解决方法
2017/10/09 Javascript
tangram.js库实现js类的方式实例分析
2018/01/06 Javascript
Vuejs在v-for中,利用index来对第一项添加class的方法
2018/03/03 Javascript
浅谈高大上的微信小程序中渲染html内容—技术分享
2018/10/25 Javascript
Python中用pycurl监控http响应时间脚本分享
2015/02/02 Python
Python图像处理之直线和曲线的拟合与绘制【curve_fit()应用】
2018/12/26 Python
Pytorch中实现只导入部分模型参数的方式
2020/01/02 Python
Python设计密码强度校验程序
2020/07/30 Python
Vs Code中8个好用的python 扩展插件
2020/10/12 Python
Python 调用 ES、Solr、Phoenix的示例代码
2020/11/23 Python
python实现定时发送邮件到指定邮箱
2020/12/23 Python
Python xlwings插入Excel图片的实现方法
2021/02/26 Python
化工专业应届生求职信
2013/11/08 职场文书
九年级化学教学反思
2014/01/28 职场文书
幼教求职信
2014/03/12 职场文书
大学计划书范文800字
2014/08/14 职场文书
幼儿园教师自我评价
2015/03/04 职场文书
酒店温馨提示语
2015/07/14 职场文书
2016元旦文艺汇演主持词(开场白+结束语)
2015/12/03 职场文书
发工资啦!教你用Python实现邮箱自动群发工资条
2021/05/10 Python
使用python绘制横竖条形图
2022/04/21 Python