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分析、压缩工具 JavaScript Analyser
Nov 30 Javascript
jquery学习笔记 用jquery实现无刷新登录
Aug 08 Javascript
javascripit实现密码强度检测代码分享
Dec 12 Javascript
javascript中普通函数的使用介绍
Dec 19 Javascript
javascript读写json示例
Apr 11 Javascript
XML文件转化成NSData对象的方法
Aug 12 Javascript
jQuery焦点图轮播插件KinSlideshow用法分析
Jun 08 Javascript
实用jquery操作表单元素的简单代码
Jul 04 Javascript
Vue2.0结合webuploader实现文件分片上传功能
Mar 09 Javascript
JavaScript实现的简单Tab点击切换功能示例
Jul 06 Javascript
微信小程序实现的图片保存功能示例
Apr 24 Javascript
javascript实现异形滚动轮播
Nov 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下实现农历日历的代码
2007/03/07 PHP
phpMyadmin 用户权限中英对照
2010/04/02 PHP
用PHP书写安全的脚本代码
2012/02/05 PHP
Fedora下安装php Redis扩展笔记
2014/09/03 PHP
PHP日期函数date格式化UNIX时间的方法
2015/03/19 PHP
php函数连续调用实例分析
2015/07/30 PHP
php验证身份证号码正确性的函数
2016/07/20 PHP
thinkphp3.2.0 setInc方法 源码全面解析
2018/01/29 PHP
jQuery ui 1.7更新小结
2009/08/15 Javascript
jquery提示 "object expected"的解决方法
2009/12/13 Javascript
在jquery中处理带有命名空间的XML数据
2011/06/13 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
JavaScript插件化开发教程(六)
2015/02/01 Javascript
JS实现选择TextArea内文本的方法
2015/08/03 Javascript
Javascript 计算字符串在localStorage中所占字节数
2015/10/21 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
获取jqGrid中选择的行的数据
2016/11/30 Javascript
jquery实现(textarea)placeholder自动换行
2016/12/22 Javascript
JavaScript mixin实现多继承的方法详解
2017/03/30 Javascript
微信小程序 判断手机号的实现代码
2017/04/19 Javascript
vue异步加载高德地图的实现
2018/06/19 Javascript
React Hooks的深入理解与使用
2018/11/12 Javascript
JS控制GIF图片的停止与显示
2019/10/24 Javascript
Vue中添加滚动事件设置的方法详解
2020/09/14 Javascript
Python中处理字符串之isalpha()方法的使用
2015/05/18 Python
Python查询阿里巴巴关键字排名的方法
2015/07/08 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
2020/02/12 Python
深入剖析webstorage[html5的本地数据处理]
2016/07/11 HTML / CSS
HTML5是否真的可以取代Flash
2010/02/10 HTML / CSS
信息部岗位职责
2013/11/12 职场文书
二年级小学生评语
2014/04/21 职场文书
群众路线教育实践活动总结
2014/10/30 职场文书
内乡县衙导游词
2015/02/05 职场文书
中班上学期个人总结
2015/02/12 职场文书
python 如何在list中找Topk的数值和索引
2021/05/20 Python
MySQL系列之十五 MySQL常用配置和性能压力测试
2021/07/02 MySQL