Рубрики
Без рубрики

От ванили JS до Vue.js: Руководство по варианту Vue

Узнайте Основы Vue.js с примерами, мигрирующими простое приложение из ванильного JS в Vue.js

Автор оригинала: Peter Mbanugo.

Vue.js является основой для строительства веб-приложений. Он имеет систему реактивности, которая позволяет вам моделировать и управлять состоянием вашего приложения такими, что когда данные изменяются, он отражается в интерфейсе UI, без необходимости запросить DOM. Если вы построили приложения в ванильном JavaScript или с jQuery, вы знаете, что вам нужно запросить элементы DOM и обновить их, чтобы отобразить некоторые данные или отображать некоторое другое состояние приложения.

Для большого приложения это становится трудно управлять. На прошлой неделе я провел несколько часов, чтобы узнать некоторые основные вещи и приняли его в боковом проекте, построенном в ванили Дж. Я хочу поделиться с вами некоторыми из моих учащихся и сравнить сторону по бокам различия в коде. Проект это список покупок Прогрессивное веб-приложение который использует Капюшон Отказ

Если вы хотите следовать, вы можете скачать Исходный код В Vanilla js пока я покажу вам, как я добавил в Vue (следуйте этому ссылка Если вы хотите прочитать о том, как я построил приложение в ванили JS, Hoodie и обслуживающем работника).

Приложение позволяет пользователям добавлять товары для покупок в список покупок. Это делается в index.html в общественной папке. Строки от 92 до 124 содержит разметку для этого:

Код для обработки сбора данных и сохранения данных находится в файле Public/JS/SRC/index.js Отказ Функция Sevenewitem () В строке 28 собирает значение из входных элементов и сохраняет элемент. Затем он связан с событием клики Добавить товар кнопка. Вот код:

function saveNewitem() {
  let name = document.getElementById("new-item-name").value;
  let cost = document.getElementById("new-item-cost").value;
  let quantity = document.getElementById("new-item-quantity").value;
  let subTotal = cost * quantity;
  if (name && cost && quantity) {
    hoodie.store.withIdPrefix("item").add({
      name: name,
      cost: cost,
      quantity: quantity,
      subTotal: subTotal
    });
    document.getElementById("new-item-name").value = "";
    document.getElementById("new-item-cost").value = "";
    document.getElementById("new-item-quantity").value = "";
  } else {
    let snackbarContainer = document.querySelector("#toast");
    snackbarContainer.MaterialSnackbar.showSnackbar({
      message: "All fields are required"
    });
  }
}

document.getElementById("add-item").addEventListener("click", saveNewitem);

Переключение на Vue.

При принятии Vue первое, что нужно добавить ссылку на Vue на вашей странице. Я добавил это к index.html следующим образом:


Я также добавил Div элемент с идентификатором приложение Чтобы окружить каждую страницу элементы внутри тега тела. Это необходимо, потому что, когда мы будем инициализировать экземпляр Vue, нам нужно сказать, какой раздел нашего приложения мы хотим его контролировать. И делая это, я говорю об этом, чтобы управлять всем внутри этого блока. Я изменил разметку, чтобы использовать некоторые VUE-директивы. Vue Директивы являются специальными атрибутами с V- приставка. Ниже приведена обновленная разметка

V-на Директива, если используется для прослушивания событий DOM. В коде выше он используется в элементе формы для прослушивания события отправки. Это также использует .prevent Модификатор, который говорит V-на Директива, чтобы позвонить Event.PreventDefault () на спусковом событии. Мы использовали V-модель Директивы на входных элементах. Он используется для создания двусторонних привязки данных на входе в форме. Он автоматически выберет правильный способ обновления элемента на основе типа ввода. Мы использовали .Number Модификатор для стоимости и количества входных элементов. То, что он делает, это автоматически попечить значение из входного элемента на номер. Это потому, что даже если набор типа – Тип = номер Значение всегда будет возвращать строку. Таким образом, эти модификаторы, которые я использовал здесь, помогает короткому замыканию некоторых проверок проверок, которые нам пришлось бы сделать.

Я создал новый файл index-vue.js Содержать код, эквивалент о том, что находится в index.js Но используя Vue. Ниже приведен код в этом файле, который создает экземпляр VUE с необходимыми свойствами для обработки событий формы и собирать данные.

const vm = new Vue({
  el: "#app",
  data: {
    name: "",
    cost: "",
    quantity: ""
  },
  methods: {
    onSubmit: function(event) {
      if (this.name && this.cost && this.quantity) {
        hoodie.store.withIdPrefix("item").add({
          name: this.name,
          cost: this.cost,
          quantity: this.quantity,
          subTotal: this.cost * this.quantity
        });

        this.name = "";
        this.cost = "";
        this.quantity = "";
      } else {
        const snackbarContainer = document.querySelector("#toast");
        snackbarContainer.MaterialSnackbar.showSnackbar({
          message: "All fields are required"
        });
      }
    }
  }
});

В разделе «Кодовой блок» я создал экземпляр VUE, проходящий его объектом, который сообщает Vue, как настроить приложение. Эль Свойство сообщает им идентификатор элемента DOM, который Vue будет выбрать и определить его территорию. На этой территории он выбирает директивы Vue (и другие вещи, связанные с Vue), и когда он инициализируется, он устанавливает привязки и обработчики событий для приложения.

данные Свойство содержит состояние приложения. Все свойства в содержащем объекте здесь будут добавлены к системе реактивности VUE, когда экземпляр VUE инициализирован. Именно эта система реактивности, которая заставляет Ui обновлять, когда одно из значений, связанных с изменениями DOM. Например, Имя Свойство связано с именем входного элемента, используя V-модель = «Имя» Директива. Эта директива устанавливает двустороннее привязку между Имя и входной элемент такой, что когда символ добавляется или удален в поле ввода, он обновляет Имя Свойство, которое будет вызывать значение ввода, чтобы отразить текущее значение Имя Отказ То же самое, другие элементы, связанные с Имя также изменится в качестве типов пользователей значение.

Методы Свойство содержит функции. Код выше определяет OnSubmit () Функция, связанная с событием отправки формы.

OnsUbmit Функции сохраняют элемент с капюшоном. Я хочу отобразить элементы, добавленные в таблицу в пользовательском интерфейсе. Приложение Vanilla JS имело следующую разметку:

Item Name Cost Quantity Sub-total

В разметке выше я использовал микро-шаблон, потому что таблица будет содержать динамические данные, и я хочу, чтобы способ заменить некоторой заполнителем реальными данными и прикрепить его к DOM.

Ниже приведен код, который отображает элементы в интерфейсе UI, как это добавлено:

function addItemToPage(item) {
  if (document.getElementById(item._id)) return;
  let template = document.querySelector("#item-row").innerHTML;
  template = template.replace("{{name}}", item.name);
  template = template.replace("{{cost}}", item.cost);
  template = template.replace("{{quantity}}", item.quantity);
  template = template.replace("{{subTotal}}", item.subTotal);
  template = template.replace("{{row-id}}", item._id);
  template = template.replace("{{item-id}}", item._id);
  document.getElementById("item-table").tBodies[0].innerHTML += template;
  
  let totalCost = Number.parseFloat(
    document.getElementById("total-cost").value
  );
  
  document.getElementById("total-cost").value = totalCost + item.subTotal;
}

hoodie.store.withIdPrefix("item").on("add", addItemToPage);

В разделе «Кодовой блок выше» он получает шаблон сценария из DOM, заменяет заполненные заполнители фактическими данными, а затем добавляет его к DOM. Общая стоимость также рассчитывается и отображается в UI.

Vue альтернатива

Переход к Vue Я удалил шаблон сценария со страницы и обновил элемент таблицы для использования Vue V-для Директива, которая будет петлен по свойству данных, которое содержит элементы. Ниже разметки

Item Name Cost Quantity Sub-total
{{ item.name}} {{ item.cost}} {{ item.quantity}} {{ item.subTotal}}

Total Cost: {{ total }}

Там нет большого изменения в разметке. Я скопировал контент от предыдущих микро-шаблонов и использованных руководителей Vue и текстовой интерполяции. Я использую V-для Директива оказать список предметов, которые будут получены из свойства данных под названием Предметы Отказ Соответствующие колонны оказывают данные с использованием текстовой интерполяции Vue {{item.name}} Отказ Это похоже на заполнитель, который мы использовали с микро-шаблоном. Всего отображается на странице, используя текстовую интерполяцию.

Обновление кода JavaScript в index-vue.js даст нам следующее:

const vm = new Vue({
  el: "#app",
  data: {
    name: "",
    cost: "",
    quantity: "",
    items: []
  },
  computed: {
    // a computed getter
    total: function() {
      // `this` points to the vm instance
      return this.items.reduce(
        (accumulator, currentValue) => accumulator + currentValue.subTotal,
        0
      );
    }
  },
  methods: {
    .....
  }
});

hoodie.store.withIdPrefix("item").on("add", item => vm.items.push(item));

Адаптация Vue намного короче и проще. То, что я сделал в коде выше, было добавить свойство данных Предметы , что такое используется в V-для Директива видела ранее. Когда элемент добавляет толстовки вызывает функцию, которая работает vm.items.push (товар) Чтобы обновить состояние и с помощью реактивной системы Vue, UI автоматически обновляется. Для расчета всего нет необходимости отслеживать предметы в доме. Я использовал компьютерное свойство, которая запускает функцию уменьшения Предметы Отказ Сейчас с реактивной системой Vue, UI обновляется всякий раз, когда любые из этих значений меняются. Хорошее вот в том, что мне не нужно беспокоиться о манипулировании DOM в моем коде. Таким образом, в меньшем количестве строк кода мы достигли того, что требуется больше кода при использовании ванильных JS (я считаю, что это похожее с jQuery).

После добавления элементов я хочу сохранить их для более поздней ссылки и сможет добавить другой список покупок. У меня есть кнопка Сохранить список Что соберут предметы, сохраняют их как группу элементов с капюшоном, и позволяет пользователю добавить новый набор элементов.

Версия Vanilla JS имела кнопку, связанную с событием клики. Ниже приведена разметка и код, который сделал его работу

//index.html
//index.js
function saveList() {
  let cost = 0;

  hoodie.store
    .withIdPrefix("item")
    .findAll()
    .then(function(items) {
      for (var item of items) {
        cost += item.subTotal;
      }

      //store the list
      hoodie.store.withIdPrefix("list").add({
        cost: cost,
        items: items
      });

      //delete the items
      hoodie.store
        .withIdPrefix("item")
        .remove(items)
        .then(function() {
          //clear the table
          document.getElementById("item-table").tBodies[0].innerHTML = "";

          //notify the user
          var snackbarContainer = document.querySelector("#toast");
          snackbarContainer.MaterialSnackbar.showSnackbar({
            message: "List saved succesfully"
          });
        })
        .catch(function(error) {
          //notify the user
          var snackbarContainer = document.querySelector("#toast");
          snackbarContainer.MaterialSnackbar.showSnackbar({
            message: error.message
          });
        });
    });
}

window.pageEvents = {
  deleteItem: deleteItem,
  saveList: saveList
  ....
};

Vue альтернатива

Переход на Vue не потребовал большую разницу. Мне все еще приходилось связываться со событием щелчков и добавленным методом обработчика событий в свойство методов в объекте параметров Vue во время инициализации.

Ниже приведена разметка для него:

@ Нажмите = "Savelist" это сокращение для V-ON: Нажмите = Savelist " который используется для прослушивания события DOM. То же самое Savelist Функция из версии Vanilla JS добавляется в свойство методов vue объекта.

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

Эта страница имеет свою разметку в Public/history.html и код для управления страницей в Public/JS/SRC/History.js Отказ Эта страница поделится некоторым кодом общего с index.html Какой навигационный бар на вершине. Навигационная панель содержит ссылки ссылки на разные страницы, Вход и Регистрация Ссылки, которые при нажатии приносят вход в систему или регистрировать диалоговые окна, а Подпись кнопка.

В версии приложения, использующего Vanilla JS, я дублирующую одну и ту же HTML-разметку на обеих страницах. Ниже приведена разметка для панели навигации:

Из разметки вы можете увидеть, что при нажатии ссылок на логин, регистрируйте и выйти из системы, они называют своими соответствующими методами. Эти обработчики событий страницы определены в index.js.

import * as shared from "shared.js";

....

shared.updateDOMLoginStatus();
window.pageEvents = {
  showLogin: shared.showLoginDialog,
  showRegister: shared.showRegisterDialog,
  signout: shared.signOut
};

The actual functions that gets called are defined in `shared.js`. Below are the functions in `shared.js` responsible for the navigation bar:


//register dialog element
let loginDialog = document.querySelector("#login-dialog");
dialogPolyfill.registerDialog(loginDialog);
let registerDialog = document.querySelector("#register-dialog");
dialogPolyfill.registerDialog(registerDialog);

let showLoginDialog = function() {
  loginDialog.showModal();
};

let showRegisterDialog = function() {
  registerDialog.showModal();
};

let showAnonymous = function() {
  document.getElementsByClassName("login")[0].style.display = "inline";
  document.getElementsByClassName("login")[1].style.display = "inline";
  document.getElementsByClassName("register")[0].style.display = "inline";
  document.getElementsByClassName("register")[1].style.display = "inline";
  document.getElementsByClassName("logout")[0].style.display = "none";
  document.getElementsByClassName("logout")[1].style.display = "none";
};

let showLoggedIn = function() {
  document.getElementsByClassName("login")[0].style.display = "none";
  document.getElementsByClassName("login")[1].style.display = "none";
  document.getElementsByClassName("register")[0].style.display = "none";
  document.getElementsByClassName("register")[1].style.display = "none";
  document.getElementsByClassName("logout")[0].style.display = "inline";
  document.getElementsByClassName("logout")[1].style.display = "inline";
};

let updateDOMLoginStatus = () => {
  hoodie.account.get("session").then(function(session) {
    if (!session) {
      // user is singed out
      showAnonymous();
    } else if (session.invalid) {
      // user is signed in, but session is no longer authenticated
      showAnonymous();
    } else {
      // user is signed in
      showLoggedIn();
    }
  });
};

let signOut = function() {
  hoodie.account
    .signOut()
    .then(function() {
      showAnonymous();
      let snackbarContainer = document.querySelector("#toast");
      snackbarContainer.MaterialSnackbar.showSnackbar({
        message: "You logged out"
      });
      location.href = location.origin;
    })
    .catch(function() {
      let snackbarContainer = document.querySelector("#toast");
      snackbarContainer.MaterialSnackbar.showSnackbar({
        message: "Could not logout"
      });
    });
};

export {
  signOut,
  showRegisterDialog,
  showLoginDialog,
  updateDOMLoginStatus
};

Этот код экспортирует функции, которые использовались в index.js Отказ ShowLogindialog () и ShowregisterDialog () Функции отображают модаль для входа в систему и регистрацию соответственно. Подпись () Функции регистрируют пользователь и звонки ShowAnonymous () который скрывает Выход из системы ссылка и показывает только Регистрация и Вход Ссылки. Функция UpdatedomLoginstatus Проверяет, будет ли пользователь аутентифицирован и отображает соответствующие ссылки. Эта функция вызывается, когда страница нагрузки.

Достижение общей навигационной панели требуется дублирующего разметки и запросы элементов DOM и нанесение CSS для отображения и скрытия ссылок в панели навигации. Давайте посмотрим на Vue альтернативу.

Vue альтернатива

Многие веб-приложения имеют порции, которые одинаковы на страницах, например, навигационные заголовки. Они должны быть абстрагированы в какой-то контейнер или компонент. Vue предоставляет то, что называется компонентом, который можно использовать для решения проблемы навигационной панели в этом примере. Vue Components являются автономными и воспроизводимыми.

Переход к компонентам Vue, я создал новый файл shared-vue.js Отказ Внутри этого я определил VUE компонент для навигационного полоса следующим образом:

Vue.component("navigation", {
  props: ["isLoggedIn", "toggleLoggedIn"],
  template: ``,
  methods: {
    showLogin: function() {
      const loginDialog = document.querySelector("#login-dialog");
      dialogPolyfill.registerDialog(loginDialog);
      loginDialog.showModal();
    },
    showRegister: function() {
      const registerDialog = document.querySelector("#register-dialog");
      dialogPolyfill.registerDialog(registerDialog);
      registerDialog.showModal();
    },
    logout: function() {
      hoodie.account
        .signOut()
        .then(() => {
          this.toggleLoggedIn();
        })
        .catch(error => {
          alert("Could not logout");
        });
    }
  }
});

В указанном выше коде мы зарегистрировали Vue компонент с именем навигация С объектом параметров, аналогично тому, что мы использовали при создании экземпляра VUE. Первая недвижимость – это реквизит Отказ Реквиты – это способ передачи данных к компоненту. Компонент может определить свои собственные данные, но в тех случаях, когда используются элемент приложения состояния при различных компонентах, используются реквизиты. isloggedin Оригация содержит логическое значение, показывающее, если пользователь аутентифицирован или нет.

Второе свойство Шаблон Содержит разметку, которая будет отображаться на странице. Разметка практически точно такая же, как альтернатива Vanilla JS в предыдущем разделе, за исключением того, что мы использовали две директивы Vue, V-шоу и @ yclick Отказ V-шоу Атрибут используется для условного рендеринга. Здесь я говорю это, чтобы показать Выход из системы Ссылка, когда isloggedin верно или показать Вход и Регистрация Ссылки, когда это ложь. Vue также предоставляет V-если и v-else Для условного рендеринга вы можете прочитать больше о них здесь Отказ @ yclick атрибут – это сокращение для V-on: нажмите Директива. Я установил ShowLogin , Showregister и Выход из системы в качестве обработчиков событий для кликов событий соответствующих ссылок.

Эти функции определены в свойстве методов. Выход из системы Функция после успешного подписания, звонки this.toggleLoggedin () Какие реквизиты передаются на этот компонент. Это будет выполнять функцию пропущенной реквизиты и, как ожидается, изменит значение isloggedin Реквизирует, что этот компонент не может изменить. Когда он меняется, система реактивности VUE будет соответственно обновлять DOM.

Этот компонент добавлен в index.html вроде как пользовательский элемент. Я сняту на навигационную панель разметки из строк 59 до 84 и замените его следующим


В коде JavaScript мы объявили реквизиты isloggedin и toggleloggedin , но при прохождении реквизитов эти значения используют эквиваленты к кебабу. Это связано с тем, что атрибуты HTML нечувствительны к регистру. Я использовал V-bind Директива пропускать значения для этих реквизитов динамически. Без этой директивы это будет передано как статическое значение, а компонент получит строку isloggedin вместо логического значения. Мы также можем использовать Shothand : для V-bind И это можно повторно написано как <навигация>

Ценность isloggedin это заявление и toggleloggedin Это метод, объявленный в экземпляре Vue в index-vue.js следующим образом

const vm = new Vue({
  el: "#app",
  data: {
    name: "",
    cost: "",
    quantity: "",
    items: [],
    isLoggedIn: false
  },
  computed: {
    .....//collapsed code
  },
  methods: {
    toggleLoggedIn: function() {
      this.isLoggedIn = !this.isLoggedIn;
    },
    ......//collapsed code
  }
});

.....//collapsed code

hoodie.account.get("session").then(function(session) {
  if (!session) {
    // user is singed out
    vm.isLoggedIn = false;
  } else if (session.invalid) {
    vm.isLoggedIn = false;
  } else {
    // user is signed in
    vm.isLoggedIn = true;
  }
});

С помощью Vue альтернативы, которую я устранил дублирующую разметку, и если в будущем мне нужно сделать любые изменения для него, я сделаю это из одного местоположения, и это делается с использованием Vue Component. Я удалял необходимость прохождения/запроса DOM, чтобы выбрать, какие элементы отображаются или скрыты на основе состояния аутентификации.

Вход и Регистрация Ссылки показывают модаль, который позволяет пользователю вводить имя пользователя и пароль, чтобы получить аутентификацию. Разметка для обоих дублируется на страницах, как навигационная панель. Это можно увидеть по линиям 171-244 в index.html и линии от 100 до 158 в История .html Отказ


  

Login

Login

Код для обработки как входа в систему, так и регистрации определен в shared.js и используется в index.js.

//shared.js

//register dialog element
let loginDialog = document.querySelector("#login-dialog");
dialogPolyfill.registerDialog(loginDialog);
let registerDialog = document.querySelector("#register-dialog");
dialogPolyfill.registerDialog(registerDialog);

let closeLoginDialog = function() {
  loginDialog.close();
};

let closeRegisterDialog = function() {
  registerDialog.close();
};

let showAnonymous = function() {
  ...
};

let showLoggedIn = function() {
  ....
};

let signOut = function() {
  ....
};

let updateDOMLoginStatus = () => {
  ....
};

let login = function() {
  let username = document.querySelector("#login-username").value;
  let password = document.querySelector("#login-password").value;

  hoodie.account
    .signIn({
      username: username,
      password: password
    })
    .then(function() {
      showLoggedIn();
      closeLoginDialog();

      let snackbarContainer = document.querySelector("#toast");
      snackbarContainer.MaterialSnackbar.showSnackbar({
        message: "You logged in"
      });
    })
    .catch(function(error) {
      console.log(error);
      document.querySelector("#login-error").innerHTML = error.message;
    });
};

let register = function() {
  let username = document.querySelector("#register-username").value;
  let password = document.querySelector("#register-password").value;
  let options = { username: username, password: password };

  hoodie.account
    .signUp(options)
    .then(function(account) {
      return hoodie.account.signIn(options);
    })
    .then(account => {
      showLoggedIn();
      closeRegisterDialog();
      return account;
    })
    .catch(function(error) {
      console.log(error);
      document.querySelector("#register-error").innerHTML = error.message;
    });
};

export {
  register,
  login,
  closeRegisterDialog,
  closeLoginDialog,
  ...
};

index.js.

//index.js

window.pageEvents = {
  closeLogin: shared.closeLoginDialog,
  showLogin: shared.showLoginDialog,
  closeRegister: shared.closeRegisterDialog,
  showRegister: shared.showRegisterDialog,
  login: shared.login,
  register: shared.register,
  signout: shared.signOut
};

Vue альтернатива

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

Vue.component("login-dialog", {
  data: function() {
    return {
      username: "",
      password: ""
    };
  },
  props: ["toggleLoggedIn"],
  template: `
      

Login

`, methods: { closeLogin: function() { const loginDialog = document.querySelector("#login-dialog"); dialogPolyfill.registerDialog(loginDialog); loginDialog.close(); }, login: function(event) { hoodie.account .signIn({ username: this.username, password: this.password }) .then(() => { this.toggleLoggedIn(); this.closeLogin(); }) .catch(error => { console.log(error); document.querySelector("#login-error").innerHTML = "Error loggin in"; }); } } });

Он зарегистрирован в данных, реквизитах, шаблонах и методах, так как свойства объекта параметров, передаваемых на Vue.component () Отказ Затем на страницах я заменяю на пользовательском элементе Vuue

//index.html

Подобные шаги относятся к диалогу регистрации, который я пропустил.

Я также пропустил, показывая некоторые части приложения, чтобы избежать показывать дубликат Vue синтаксиса. Следуйте этим ссылка Если вы хотите узнать, как я построил все шаг на шаг. Он также объяснил такие понятия, как Сервисные работники и Нажмите API.

До сих пор я показал вам некоторые из изменений, которые я сделал в мою приложение во время перехода из ванили JS в Vue.js. Не сложно начать использовать Vue, если вы только что узнали, как создавать веб-приложения с HTML, CSS и JavaScript (или jQuery). Вам не нужно знать ES6 или понять любой шаг сборки, чтобы начать. Я добился меньшего количества дублирования кода и лучшую организацию кода при использовании Vue. Я охватил только основные вещи, которые вам нужно понять, чтобы начать использовать Vue, но, конечно, есть больше для Vue. В будущем пост я буду охватывать больше концепций, так как я продолжаю копаться в нее и, надеюсь, поделитесь тем, как построить довольно сложные приложения для одиночных страниц.

Вы можете найти полный код для приложений Vanilla JS и Vue.js на GitHub, используя ссылки ниже.

Также поделился на Dev.to.