Рекомендуемое чтение:
Реализуйте очень простое двустороннее привязка данных JS
MVVM-очень популярная модель разработки для веб-фронта. Использование MVVM может сделать наш код больше внимания на борьбе с бизнес -логикой, а не на заботе о операциях DOM. В настоящее время знаменитые фреймворки MVVM включают VUE, Avalon, React и т. Д. Из любопытства и готовности к борьбе я также написал самую простую библиотеку MVVM (MVVM.JS) в этом направлении, в общей сложности более 2000 строк кода. Наименование и использование инструкций похожи на VUE. Здесь я поделюсь принципами реализации и идеями своей кодовой организации.
Идеи сортировка
MVVM - это концептуально шаблон, который действительно отделяет представления от логики данных, а ViewModel - это в центре внимания всего шаблона. Для реализации ViewModel вам необходимо связать модель данных (модель) и представление (View). Вся идея реализации может быть просто суммирована в 5 баллов:
Реализовать компилятор для сканирования и извлечения инструкций для каждого узла элемента;
Реализуйте анализатор, чтобы анализировать инструкции по элементу, которые могут обновить намерение инструкции для DOM с помощью функции обновления (модуль, который может быть специально отвечать за обновление просмотра в середине). Например, при анализе узла <p v-she-show = "isshow"> </p> сначала получите значение isshow в модели, а затем измените node.style.display в соответствии с iSshow для управления дисплеем и скрытия элементов;
Реализация наблюдателя может связать функцию обновления каждой инструкции в парсере с полями, соответствующими модели;
Реализуйте наблюдателя, чтобы отслеживать изменение значения всех полей объекта, и как только изменение происходит, можно получить последнее значение, и можно запустить обратный вызов уведомления;
Используйте наблюдатель, чтобы установить мониторинг модели в наблюдателе. Когда значение в модели изменяется, мониторинг запускается. После того, как наблюдатель получит новое значение, он вызывает функцию обновления, связанную на шаге 2, которая может достичь цели обновления представления при изменении данных.
Эффект пример
Во -первых, давайте посмотрим на последний пример использования, который похож на экстремацию других фреймворков MVVM:
<div id = "mobile-list"> <h1 v-text = "title"> </h1> <ul> <li v-for = "item в брендах"> <b v-text = "item.name"> </b> <span v-show = "showrank"> rank: {item.ranc document.queryselector ('#mobile-list'); var vm = new mvvm (element, {'title': 'list', 'showrank': true, 'brands': [{'name': 'Apple', 'Rank': 1}, {name ':' Galaxy ',' Rank ': 2}, {name': 'Oppo', ',', ',' name ',' rank ':' nam 3}]}); vm.set ('title', 'Top 3 List Mobile Rank'); // => <H1> Список мобильных рангов Top 3 Mobile </H1>Модульное подразделение
Я разделил MVVM на пять модулей для реализации: компилятор компиляции, анализатор, просмотр модуля обновления, наблюдатель за модулем подписки на данные и наблюдатель модуля прослушивания данных. Процесс может быть кратко описан как: после компилятора компилятора команда, информация об инструкции передается анализатору для анализа. Сигсерчик обновляет начальное значение и подписывается на наблюдателя за изменениями в данных. Наблюдатель отслеживает изменение данных, а затем подает их обратно к наблюдателю. Наблюдатель уведомляет обновляющий результат изменения и находит соответствующую функцию обновления, чтобы обновить представление.
Приведенный выше процесс показан на рисунке:
Ниже приведено описание основных принципов реализации этих пяти модулей (код размещается только на ключевых частях, перейдите на мой GitHub для полной реализации)
1. Компиляционный компилятор модуля
Ответственность компилятора является в основном за сканирование и извлечение инструкций для каждого узла элемента. Поскольку процесс компиляции и анализа будет много раз проходить все дерево узлов, чтобы повысить эффективность компиляции, в конструкторе MVVM, сначала преобразуйте элемент в копию фрагментов документа. Объект компиляции является фрагментом документа и не должен быть целевым элементом. После того, как все узлы составлены, фрагмент документа добавляется обратно в исходный настоящий узел.
VM.complieElement реализует сканирование и извлечение инструкций всех узлов элемента:
vm.compileelement = function (фрагмент, корень) {var node, childnodes = fragment.childnodes; // сканирование дочернего узла для (var i = 0; i <childnodes.length; i ++) {node = childnodes [i]; if (this.hasdirective (node) {this. $ ensempilEnodes. Сканируйте дочерний узел детского узла if (node.childnodes.length) {this.compileelement (node, false);}} // Сканирование дочерних узлов if (root) if (root) {this.compileallnodes ();}}Метод vm.compileallnodes будет компилировать каждый узел в этом. После составления узла он будет удален из очереди кэша. В то же время проверьте это. Вы можете добавить фрагменты документа в настоящий узел.
2. Диаграмм анализа модуля инструкции
Когда компилятор компилятора извлекает инструкции из каждого узла, его можно отправлять в анализатор для анализа. Каждая инструкция имеет различный метод анализа. Все инструкции должны делать только две вещи: одна заключается в том, чтобы обновить значение данных для представления (начальное состояние), а другая - подписать функцию обновления на мониторинг изменений модели. Здесь мы используем V-Text в качестве примера для описания общего метода анализа директивы:
parser.parsevtext = function (node, model) {// Получить начальное значение, определенное в модели var text = this. $ model [model]; // Обновление Text node.textContent = text; // Соответствующая функция обновления: // updater.updateNodetextcontent (node, text); // подписать на изменение модели. {node.textContent = last; // updater.updateNetextContent (node, text);});}3. Наблюдатель модуля подписки на данные
В предыдущем примере наблюдатель предоставляет метод наблюдения для подписки на изменения данных. Одним из параметров является модель поля модели, а другой - функция обратного вызова. Функция обратного вызова запускается через наблюдатель. Новое значение последнего и старое значение старое значение передается в параметре. После того, как наблюдатель получит новое значение, он может найти соответствующий обратный вызов (функция обновления) модели для обновления представления. Функции модели и обновления-это отношение от одного ко многим, то есть модель может иметь столько функций обратного вызова (функции обновления), которые обрабатывают ее, например: v-Text = "title" и v-html = "Название"
Добавить подписку на данные в Watcher.Watch Метод реализации:
Watcher.watch = function (Field, callback, context) {var callbacks = this. $ watchcallbacks; if (! object.hasownproperty.call (this. $ model, field)) {console.warn ('Поле:' + Field + 'не существует в модели! [];} // обратные вызовы кэша [Field] .push ([callback, context]);}Когда полевое поле модели данных меняется, наблюдатель запускает все обратные вызовы в массиве кэша, которые подписались на поле.
4. Наблюдатель модуля модуля данных
Наблюдатель является основной основой всей реализации MVVM. Я прочитал статью, в которой говорится, что OO (Object.Observe) зажигает революцию по связыванию данных и окажет огромное влияние на фронт. К сожалению, проект ES7 отказался от OO! В настоящее время нет поддержки браузеров! К счастью, есть также объект. DefineProperty, которая может имитировать простого наблюдателя, перехватывая дескрипторы доступа (Get и Set) свойств объекта:
// перехватывают методы получения и установки свойства Prop объекта объекта object.defineproperty (Object, prop, {get: function () {return this.getValue (Object, prop);}, set: function (newValue) {var oldValue = this.getValue (Object, prop); if (newValue! Изменение триггера обратное вызовТогда есть еще один вопрос: как контролировать операции массива (толчок, сдвиг и т. Д.)? Все рамки MVVM реализуются путем переписывания прототипа массива:
stemver.rewritearraymethods = function (массив) {var self = this; var arrayproto = array.prototype; var arraymethods = object.create (arrayproto); var methods = 'push | pop | shift | untheft | splice | sort | reample'.split (' | '); Methods.foreach (function (method) {object.defineproperty (arraymethods, method, function () {var i = arguments.length; var original = arrayproto [method]; var args = new Array (i); while (i--) {Args [i] = аргументы [i];} var result = argy.apply (это, Args); метод); return result;});}); Array .__ Proto__ = Arraymethods;}Этот метод реализации ссылается на Vue. Я думаю, что он используется очень хорошо, но атрибут длины массива нельзя прослушать, поэтому в MVVM следует избегать операции по длине.
5. Просмотреть модуль обновления
Updater является самым простым среди пяти модулей, вам нужно отвечать только за функцию обновления, соответствующую каждой инструкции. Например, после серии подбрасывания и оставления окончательного результата для обновления обновления или обновлений событий, функция обновления V-текста:
Updater.updateNeTextContent = function (node, text) {node.textContent = text;}Обновить функцию V-Bind: стиль:
Updater.updatenodestyle = function (node, свойство, значение) {node.style [propperty] = value;}Реализация двусторонней привязки данных
Двунаправленное связывание данных элементов формы является одной из самых больших особенностей MVVM:
Фактически, принцип реализации этой магической функции также очень прост. Есть только две вещи: одна - обновить значение формы при изменении данных, а другая - обновить данные при изменении значения формы, чтобы значение данных было связано со значением формы.
Изменения данных для обновления значений формы могут быть легко выполнены, используя упомянутый выше модуль наблюдателя:
Watcher.watch (model, function (last, old) {input.value = last;}); 'Чтобы обновить данные в изменениях формы, вам нужно прослушать, что стоит изменять события в режиме реального времени и обновить соответствующие поля модели данных:
var model = this. $ model; input.addeventlistenr ('change', function () {model [field] = this.value;}); 'Другие формы радио, флажок и выбора являются одним и тем же принципом.
Вышеуказанное было объяснено весь процесс и основные идеи реализации каждого модуля. В первый раз, когда я опубликовал статью в сообществе, мои навыки выражения языка не очень хороши. Если есть какие -либо неправильные слова и плохие вещи, я надеюсь, что каждый сможет критиковать и исправить их!
Заключение
Я пробую этот простой Mvvm.js, потому что я использовал Vue.js в своем фреймворк -проекте, но я просто использовал его систему инструкций. Многие функции использовались только около четверти. Я думал, что этого будет достаточно, чтобы просто реализовать связывание данных и просмотр. В результате я не нашел такую библиотеку JavaScript, поэтому я сам создал такое колесо.
Хотя функции и стабильность гораздо меньше, чем популярные рамки MVVM, такие как VUE, и реализация кода может быть относительно грубой
В настоящее время мой MVVM.JS только реализует самую основную функцию. Я буду продолжать улучшать и укреплять его в будущем. Если вы заинтересованы, пожалуйста, обсудите и улучшите его вместе ~