js skills: дюжина строк кода для реализации vue.watch

внешний интерфейс JavaScript Vue.js анимация

В последнее время я был занят, как собака, и некоторое время не обновлялся.Хотя я зомби-блогер, я все еще должен ворчать о небольшом выигрыше.

Я полагаю, что многие люди, использующие Vue, знают, что принцип двусторонней привязки Vue основан на привязке геттеров и сеттеров к свойствам и запуске повторного рендеринга представлений при изменении свойств. И этот выпуск также использует эти два встроенных метода для реализации watch в vue.

геттеры и сеттеры

Геттер — это способ получить значение свойства, а сеттер — это способ установить значение свойства.

свойство присвоеноa = 1, сработает сеттер в прототипе a;

а такжеconsole.log(a), будет запущен геттер внутри прототипа a.

Реализовать геттеры и сеттеры

Мы не можем напрямую связать функции событий с сеттерами и геттерами переменных.Для достижения привязки нам нужно использовать объект Object для создания свойств с сеттерами и геттерами.

Вот краткое изложение предшественниковНесколько способов реализации геттеров и сеттеров, и он также суммирует некоторые неявные свойства в 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. ложный

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;

Добавить триггер события просмотра

/**
 * @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;
  1. Для надежности внутри функцииgetBaseTypeиспользуется для проверки типов.
  2. Object.defineProperty(this), это указывает контекст на текущий объект.
  3. this.$watch[_key].call(this,val,oldVal), Привяжите страницу контекста события прослушивания к текущему объекту, чтобы значение в объекте можно было получить через это в часах, следующим образом
let wm = new watcher({
    data:{
        a: 0,
        b: 'hello'
    },
    watch:{
        a(newVal,oldVal){
            console.log(this.b);
        }
    }
})

Суммировать

Некоторые люди могут спросить, почему бы не использовать vue напрямую. Вы также знаете, что vue — это фреймворк инженерного уровня.Конечно, для более крупных проектов используются vue и react, но используете ли вы также vue для отображения официального веб-сайта или мобильной промо-страницы H5? Это, конечно, не нужно.

Используя этот класс наблюдателя, вы можете сделать управление состоянием вашей страницы организованным и отслеживаемым.

Например, когда несколько кнопок связаны с изменениями и анимацией одного или нескольких представлений, вам не нужно запускать модификацию при нажатии каждой кнопки.

 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';
 }

Но если ваше представление не связано более чем двумя действиями, оно не может быть использовано.