Vue V-модель и прокси первый набор не называется - PullRequest
0 голосов
/ 05 сентября 2018

В настоящее время я работаю над проектом Vue, в котором я хочу иметь класс модели, который хранит все свои начальные данные в двух свойствах: original и attributes. Однако у меня возникают трудности с привязкой свойств к входу через v-model.

Допустим, у меня есть следующий класс:

class Model
{
    constructor () {
        return new Proxy(this, {
            get: (target, property, receiver) => {
                console.log('get');
                return target[property];
            },

            set: (target, property, value, receiver) => {
                console.log('set');
                target[property] = value + 123;
                return true;
            }
        });
    }
}

Этот класс будет регистрировать get при получении свойства и set при установке свойства. Также при настройке он добавит 123 в конце значения. Будет выполнено следующее:

let model = new Model();

model.name = 'test'; // Logs: 'set'

console.log(model.name); // Logs: 'get' and 'test123'

Это работает как ожидалось.

Проблемы начинаются, когда я связываю эти свойства со входом через v-model. Происходит следующее:

Действия выполняются:

<input v-model="model.name" />
...
data () {
    return {
        model: new Model
    };
}

При первом изменении свойство name будет добавлено к объекту model. Нет журнала вообще. Без добавления 123 в конце значения. Значение модели изменилось на { model: 't' }.

Второе изменение будет записывать set и добавит 123. Значение модели изменилось на { model: 'te123' }.

Регистрация аргументов вызова set во время второго изменения: Model {__ob__: Observer}, "name", "te", Proxy {__ob__: Observer}

Кто-нибудь имел эту проблему раньше или знает, что здесь происходит?

После ответа @ sphinx

Спасибо за ваш ответ! Это работает!

Чтобы сделать вещи более сложными, я хочу, чтобы свойства, которые находятся в определенном массиве fillable, были установлены в свойстве под названием attributes. Однако возвращается то же поведение.

class Model
{
    constructor () {
        this.attributes = {};
        this.fillable = ['name'];

        return new Proxy(this, {
            get: (target, property, receiver) => {
                console.log('get', property);

                if (target.fillable.indexOf(property) > -1) { // Check if in fillable
                    if (!(property in  target.attributes)) {
                        Vue.set(target.attributes, property, null);
                    }

                    return target.attributes[property];
                }

                return target[property];
            },
            set: (target, property, value, receiver) => {
                console.log('set', property, value);

                if (target.fillable.indexOf(property) > -1) {
                    Vue.set(target.attributes, property, value + 123);
                } else {
                    target[property] = value
                }

                return true;
            }
        });
    }
}
Vue.config.productionTip = false

new Vue({
  el: '#app',
  data() {
    return {
      test: new Model
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>

<div id="app">
  <span>{{test.name}}</span>
    <input v-model="test.name" type="text">
</div>

Во время первого изменения свойство name устанавливается непосредственно для объекта model. Но метод set не вызывается.

Во время второго изменения свойство name изменяется и вызывается метод set.

Любые предложения о том, почему это происходит?

1 Ответ

0 голосов
/ 06 сентября 2018

В вашем примере, получатель создаст одно свойство, но это не реактивность (см. Руководство по Vue: Реактивность по глубине ).

Так Vue не может отслеживать изменения .

Решение простое, как показано выше в руководстве, использует Vue.set или vm.$set для проверки реактивности вашего объекта.

Как показано ниже:

class Model
{
    constructor () {
        return new Proxy(this, {
            get: (target, property, receiver) => {
                console.log('get', property);
                if(!(property in target)) Vue.set(target, property, null)
                return target[property]
            },
            set: (target, property, value, receiver) => {
                console.log('set', property, value);
                Vue.set(target, property, value + 123)
                return true;
            }
        });
    }
}
Vue.config.productionTip = false
new Vue({
  el: '#app',
  data() {
    return {
      test: new Model
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>

<div id="app">
  <span>{{test.name}}</span>
    <input v-model="test.name" type="text">
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...