Когда вам нужно что-то ввести в Vue, вы, естественно, подумаете об использовании<input v-model="xxx" />
способ достижения двусторонней привязки. Ниже приведен самый простой пример
<div id="app">
<h2>What's your name:</h2>
<input v-model="name" />
<div>Hello {{ name }}</div>
</div>
new Vue({
el: "#app",
data: {
name: ""
}
});
Демонстрация JsFiddle
Затем будет отображено то, что вводится в поле ввода этого примера. Это нативная пара Vue<input>
Это также типичный пример двусторонней передачи данных между родительским и дочерним компонентами. ноv-model
Это новая функция, добавленная в Vue 2.2.0, до этого Vue поддерживал только односторонний поток данных.
Односторонний поток данных в Vue
Односторонний поток данных Vue подобен React.Родительский компонент может передавать данные дочернему компоненту, устанавливая свойства (Props) дочернего компонента.Если родительский компонент хочет получить данные дочернего компонента, он должен зарегистрируйте событие с дочерним компонентом, и дочерний компонент счастлив Когда это событие запускается, данные передаются. Подводя итог в одном предложении, свойства передают данные вниз, а события передают данные вверх.
В приведенном выше примере, если вы не используетеv-model
это должно выглядеть так
<input :value="name" @input="name = $event.target.value" />
Поскольку обработка событий написана во встроенном режиме, часть сценария не нужно изменять. Но в большинстве случаев событие вообще определяется как метод, код будет намного сложнее
<input :value="name" @input="updateName" />
new Vue({
// ....
methods: {
updateName(e) {
this.name = e.target.value;
}
}
})
Из примера вышеv-model
Это экономит много кода, и самое главное, что можно определить на один обработчик событий меньше. такv-model
Фактические засушливые события включают
- использовать
v-bind
(который:
) односторонняя привязка к свойству (пример::value="name"
) - связывать
input
событие (т.@input
) в реализованный по умолчанию обработчик событий (пример:@input=updateName
- Этот обработчик событий по умолчанию изменяет связанные данные на основе значения, переданного объектом события (пример:
this.name = e.target.value
)
пользовательские компонентыv-model
Vue инкапсулирует нативные компоненты, поэтому<input>
Срабатывает при вводеinput
мероприятие. Но как насчет пользовательских компонентов? Вот пример списка задач с помощью шаблона JsFiddle Vue.
Шаблон Vue для JsFiddle
Нажмите на логотип JsFilddle и выберите шаблон Vue на всплывающей панели выше.
Стандартный код состоит из двух частей, HTML и Vue(js), и выглядит следующим образом:
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<input type="checkbox"
v-on:change="toggle(todo)"
v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
Определить компоненты Todo
Шаблон Vue JsFiddle реализует отображение списка задач по умолчанию, данные фиксируются, а весь контент заполняется в одном шаблоне. Первое, что нам нужно сделать, это превратить отдельный Todo в подкомпонент. Поскольку его нельзя записать в виде нескольких файлов в JsFiddle, компонент используетVue.component()
Определено в скрипте, в основном, чтобы поставить<li>
Выньте эту часть содержимого:
Vue.component("todo", {
template: `
<label>
<input type="checkbox" @change="toggle" :checked="isDone">
<del v-if="isDone">
{{ text }}
</del>
<span v-else>
{{ text }}
</span>
</label>
`,
props: ["text", "done"],
data() {
return {
isDone: this.done
};
},
methods: {
toggle() {
this.isDone = !this.isDone;
}
}
});
Первоначально определено в приложенииtoggle()
Метод также был немного изменен и определен в компоненте.toggle()
При вызове он изменит, завершен он или нетdone
ценность . Но из-заdone
определяется вprops
Атрибуты не могут быть назначены напрямую, поэтому для определения данных используется первый метод, рекомендованный должностным лицом.isDone
, инициализируетсяthis.done
и использовать внутри компонентаisDone
чтобы контролировать, завершено ли это состояние.
Шаблон и код соответствующего раздела App значительно уменьшены:
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<todo :text="todo.text" :done="todo.done"></todo>
</li>
</ol>
</div>
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
}
});
Демонстрация JsFiddle
Но пока данные все еще односторонние. С точки зрения эффекта, установка флажка может привести к эффекту зачеркивания, но все эти динамические изменения находятся вtodo
Компонент делается внутри, и нет проблем с привязкой данных.
Добавить счетчик в список задач
чтобыtodo
Изменения состояния внутри компонента могут отображаться в списке задач.Мы добавляем счетчик в список задач, чтобы показать количество задач, которые были выполнены. Потому что это числоtodo
Влияние внутреннего состояния (данных) компонента, требующегоtodo
Изменения внутренних данных отражаются в его родительском компоненте, так чтоv-model
использования.
Номер в названии, который мы должныn/m
форма, например2/4
Обозначает в общей сложности 4 задачи, 2 из которых выполнены. Это требует модификации шаблона и части кода Todo List, добавленияcountDone
а такжеcount
Два вычисляемых свойства:
<div id="app">
<h2>Todos ({{ countDone }}/{{ count }}):</h2>
<!-- ... -->
</div>
new Vue({
// ...
computed: {
count() {
return this.todos.length;
},
countDone() {
return this.todos.filter(todo => todo.done).length;
}
}
});
Теперь количество отображается, но теперь изменение состояния задачи не влияет на количество. Мы хотим, чтобы изменения дочернего компонента влияли на данные родительского компонента.v-model
О нем я расскажу позже, начнем с самого распространенного метода, событий:
- Подсборка
todo
существуетtoggle()
средний триггерtoggle
событие будетisDone
как параметр события - родительский компонент является дочерним компонентом
toggle
обработчик событий определения события
Vue.component("todo", {
//...
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("toggle", this.isDone);
}
}
});
<!-- #app 中其它代码略 -->
<todo :text="todo.text" :done="todo.done" @toggle="todo.done = $event"></todo>
Здесь@toggle
Связывание — это выражение. потому что здесьtodo
является временной переменной, если вmethods
Трудно связать эту временную переменную, определив специальную функцию обработки событий в прошлом (конечно, можно определить общий метод, вызвав его).
Функции обработчика событий, которые обычно непосредственно соответствуют обрабатываемым вещам, например определение
onToggle(e)
, связанный как@toggle="onToggle"
. В этом случае его нельзя передатьtodo
как параметр.Обычный метод, который можно определить как
toggle(todo, e)
, который вызывается как выражение вызова функции в определении события:@toggle="toggle(todo, $event)"。它和
todo.done = $event` Общее выражение.Обратите внимание на разницу между ними: первая — связанная функция-обработчик (ссылка), а вторая — связанное выражение (вызов).
Теперь ожидаемый эффект был достигнут через метод события
** Демонстрация скрипта Js **
изменено вv-model
Ранее мы говорили об использованииv-model
Понял, теперь его преобразовывать. Обратите внимание на реализациюv-model
несколько элементов
- дочерний компонент через
value
Опора принимает ввод - Дочерний компонент запускается
input
Выход события с параметрами массива - используется в родительском компоненте
v-model
связывать
Vue.component("todo", {
// ...
props: ["text", "value"], // <-- 注意 done 改成了 value
data() {
return {
isDone: this.value // <-- 注意 this.done 改成了 this.value
};
},
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("input", this.isDone); // <-- 注意事件名称变了
}
}
});
<!-- #app 中其它代码略 -->
<todo :text="todo.text" v-model="todo.done"></todo>
.sync
Реализовать другие привязки данных
Введение Vue 2.2.0 упоминалось ранее.v-model
характеристика. По какой-то причине его входное свойствоvalue
, но выходное событие вызываетсяinput
.v-model
,value
,input
Между этими тремя именами нет буквально никакой связи. Хотя это может показаться немного странным, дело не в этом, дело в том, что элемент управления может привязываться только к одному свойству в обоих направлениях?
Vue 2.3.0 представлен.sync
модификаторы используются для измененияv-bind
(который:
), чтобы сделать его двусторонним. Это тоже синтаксический сахар, добавляющий.sync
Привязка декорированных данных будет выглядеть какv-model
Один и тот же обработчик событий автоматически зарегистрирован для назначения значений в связанные данные. Этот подход также требует дочерних компонентов, чтобы вызвать определенные события. Однако имя этого события имеет отношение к имени свойства связывания. Он добавляется до имени свойства связывания.update:
приставка.
Например<sub :some.sync="any" />
подкомпонентыsome
свойства и родительский компонентany
Привязка данных, дочерний компонент должен пройти$emit("update:some", value)
чтобы вызвать изменение.
В приведенном выше примере используйтеv-model
Связывание всегда кажется немного неловким, потому чтоv-model
Буквальное значение состоит в том, чтобы связать значение в обоих направлениях и указать, является ли оно неполным.done
На самом деле это состояние, а не значение. Поэтому мы снова модифицируем его, все еще используяdone
это имя свойства (вместоvalue
),пройти через.sync
для достижения двусторонней привязки.
Vue.component("todo", {
// ...
props: ["text", "done"], // <-- 恢复成 done
data() {
return {
isDone: this.done // <-- 恢复成 done
};
},
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("update:done", this.isDone); // <-- 事件名称:update:done
}
}
});
<!-- #app 中其它代码略 -->
<!-- 注意 v-model 变成了 :done.sync,别忘了冒号哟 -->
<todo :text="todo.text" :done.sync="todo.done"></todo>
** Демонстрация скрипта Js **
Демистификация двусторонней привязки Vue
Из приведенного выше описания, я думаю, все должны были понять, что двусторонняя привязка Vue на самом деле завершается обычной односторонней привязкой и комбинацией событий, но черезv-model
а также.sync
Функция обработчика по умолчанию зарегистрирована для обновления данных. В исходном коде Vue есть такой абзац
// @file: src/compiler/parser/index.js
if (modifiers.sync) {
addHandler(
el,
`update:${camelize(name)}`,
genAssignmentCode(value, `$event`)
)
}
Как видно из этого кода,.sync
При двусторонней привязке компилятор добавитupdate:${camelize(name)}
Функция обработчика события для назначения данных (genAssignmentCode
буквально означает код, который генерирует присваивание).
Перспектива
В настоящее время двусторонняя привязка Vue также должна обеспечивать возврат данных путем запуска событий. Между этим и многими ожидаемыми доходами от назначений все еще существует определенный разрыв. Есть две основные причины этого разрыва
- Необходимо вернуть данные через события
- Свойства (реквизит) не могут быть назначены
В текущей версии Vue упрощение может быть достигнуто за счет определения вычисляемых свойств, таких как
computed: {
isDone: {
get() {
return this.done;
},
set(value) {
this.$emit("update:done", value);
}
}
}
По правде говоря, довольно утомительно определять больше имен переменных с одинаковым значением и разными именами. Я надеюсь, что Vue сможет сократить этот процесс с помощью определенных технических средств в будущих версиях, таких как добавление объявлений свойств (Prop).sync
вариант, просто объявитеsync: true
могут быть напрямую назначены и автоматически запущеныupdate:xxx
мероприятие.
Конечно, как фреймворк, при решении проблемы нам также нужно учитывать влияние на другие функции и расширяемость фреймворка, так что во что в итоге превратится двухсторонняя привязка, мы подождем и увидим для Vue 3.0.