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变量作用域更轻松
Oct 25 Javascript
javascript 混合的构造函数和原型方式,动态原型方式
Dec 07 Javascript
基于Jquery的仿Windows Aero弹出窗(漂亮的关闭按钮)
Sep 28 Javascript
javascript 循环调用示例介绍
Nov 20 Javascript
javascript判断是否按回车键并解决浏览器之间的差异
May 13 Javascript
JAVA中截取字符串substring用法详解
Apr 14 Javascript
微信小程序开发之实现自定义Toast弹框
Jun 08 Javascript
Gulp实现静态网页模块化的方法详解
Jan 09 Javascript
浅谈让你的代码更简短,更整洁,更易读的ES6小技巧
Oct 25 Javascript
Fetch超时设置与终止请求详解
May 18 Javascript
抖音短视频(douyin)去水印工具的实现代码
Mar 30 Javascript
JavaScript中10个Reduce常用场景技巧
Jun 21 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
2.PHP入门
2006/10/09 PHP
PHP 各种排序算法实现代码
2009/08/20 PHP
php-perl哈希算法实现(times33哈希算法)
2013/12/30 PHP
ThinkPHP模板判断输出Empty标签用法详解
2014/06/30 PHP
php实现判断访问来路是否为搜索引擎机器人的方法
2015/04/15 PHP
PHP后期静态绑定实例浅析
2018/12/21 PHP
laravel批量生成假数据的方法
2019/10/09 PHP
javascript 写类方式之三
2009/07/05 Javascript
Extjs学习过程中新手容易碰到的低级错误积累
2010/02/11 Javascript
javascript高级程序设计第二版第十二章事件要点总结(常用的跨浏览器检测方法)
2012/08/22 Javascript
javascript html5摇一摇功能的实现
2016/04/19 Javascript
jQuery ajax应用总结
2016/06/02 Javascript
jQuery 翻页组件yunm.pager.js实现div局部刷新的思路
2016/08/11 Javascript
nodejs redis 发布订阅机制封装实现方法及实例代码
2016/12/15 NodeJs
Nodejs 发送Post请求功能(发短信验证码例子)
2017/02/09 NodeJs
原生js实现可拖拽效果
2017/02/28 Javascript
AngularJS中使用three.js的实例详解
2017/07/21 Javascript
让网站自动生成章节目录索引的多个js代码
2018/01/07 Javascript
基于Vue实现拖拽功能
2020/07/29 Javascript
vue-router+nginx 非根路径配置方法
2018/06/30 Javascript
jquery检测上传文件大小示例
2020/04/26 jQuery
Python代码实现KNN算法
2017/12/20 Python
Python简单定义与使用二叉树示例
2018/05/11 Python
对python 合并 累加两个dict的实例详解
2019/01/21 Python
Python数据类型之Dict字典实例详解
2019/05/07 Python
Python实现一个数组除以一个数的例子
2019/07/20 Python
python进度条显示-tqmd模块的实现示例
2020/08/23 Python
HTML5 Canvas概述
2009/08/26 HTML / CSS
精细化工应届生求职信
2013/11/17 职场文书
外语系毕业生自荐信范文
2013/12/16 职场文书
测试工程师程序员求职信范文
2014/02/20 职场文书
《青海高原一株柳》教学反思
2014/04/25 职场文书
大学专科求职信
2014/07/02 职场文书
CSS实现九宫格布局(自适应)的示例代码
2022/02/12 HTML / CSS
2022新作动画《福星小子》释出宣传影片 加入内田真礼&宫野真守配音演出
2022/04/08 日漫
TaiShan 200服务器安装Ubuntu 18.04的图文教程
2022/06/28 Servers