视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
js技巧之十几行的代码实现vue.watch代码
2020-11-27 22:13:16 责编:小采
文档


  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个以上动作联动的话,也未必会用上。

    下载本文
    显示全文
    专题