[Необходимо для собеседования] Как внедрить VueRouter?

Vue.js
[Необходимо для собеседования] Как внедрить VueRouter?

На начальном собеседовании будет задано много очков знаний. Framework, это почти один из вопросов, которые необходимо задать. Как один из самых популярных фреймворков SPA, Vue является изюминкой процесса собеседования. Будучи чрезвычайно важной ролью в экосистеме Vue, Vue Router также является навыком, который мы должны освоить.

В этой статье вы познакомитесь с использованием Vue Router и самостоятельно реализуете простую версию Vue Router.

Обзор основ Vue Router

Шаги для использования

Сначала используйте vue cli, чтобы создать проект Vue, чтобы просмотреть использование vue router.

Установите vue-cli глобально.

npm i -g @vue/cli

После завершения установки проверьте, нормальная ли версия.

vue --version

Затем создайте демонстрационный проект.

vue create vue-router-demo

Начните с использования пользовательского выбора. Вручную выберите функции.

vue cli задаст несколько вопросов. Всего нужно выбрать три пункта Babel, Router, Linter.

Таким образом, vue cli поможет нам создать базовую структуру кода vue router.

В проект и запустить проект.

npm run serve

Затем вы можете увидеть эффект маршрутизации в браузере.

Шаги по использованию vue router в vue примерно следующие.

  1. страница маршрутизации

Создайте страницу, соответствующую маршруту.

По умолчанию в папке представлений.

  1. Зарегистрировать плагин маршрутизации

Используйте Vue.use(VueRouter) для регистрации подключаемых модулей маршрутизации. Метод Vue.use специально используется для регистрации плагинов, если функция передана, она будет вызываться напрямую. Если объект передан, будет вызван метод установки объекта.

  1. Создать объект маршрута

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

Объекты создаются с помощью нового VueRouter, а конструктор VueRouter является объектом. Задайте для свойства route этого объекта только что определенное правило маршрутизации.

По умолчанию это router/index.js.

  1. Зарегистрируйте объект маршрутизатора

Когда новый Vue, параметр маршрутизатора в объекте конфигурации устанавливается на объект маршрута, созданный выше.

  1. Создание заполнителя компонента маршрутизации

В элементе, соответствующем опции el, заданной экземпляром Vue, используйте тег router-view, чтобы создать заполнитель для компонента маршрутизации. Маршрутизируемый компонент будет отображаться в этом месте каждый раз.

  1. Создать ссылку

Используйте router-link для создания ссылок и router-link для изменения маршрутов.

Когда экземпляр Vue включает параметр маршрутизатора, объект экземпляра будет иметь еще два свойства: $route и $router.

$route — это текущий объект правила маршрутизации, в котором хранится такая информация, как пути и параметры.

$router — это объект экземпляра маршрутизации, в котором хранится множество методов маршрутизации, таких как push, replace, go и т. д. Также хранит информацию о маршрутизации, такую ​​как режим и currentRoute.

динамическая маршрутизация

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

Сначала добавьте маршрут.

Путь до :id фиксирован, а сам :id означает получение параметра id.

То, что возвращает компонент, является функцией, именно так написана ленивая маршрутизация.

То есть при срабатывании этого маршрута компонент будет отрисовываться. Когда этот маршрут не активирован, компонент не будет отображаться. Может улучшить производительность.

// ... other code
const routes = [
  // ... other code
  {
    path: "/detail/:id",
    name: "Detail",
    component: () => import("../views/Detail.vue"),
  },
];

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

<template>
  <div>当前用户ID:{{ $route.params.id }}</div>
</template>

<script>
export default {
  name: "Detail",
};
</script>

Это первый способ получить параметры динамической маршрутизации через правила маршрутизации для получения параметров.

Но этот подход имеет тот недостаток, что зависимость от $route работает должным образом.

Есть еще один способ уменьшить эту зависимость.

Включите атрибут props в правиле маршрутизации.

// ... other code
const routes = [
  // ... other code
  {
    path: "/detail/:id",
    name: "Detail",
    props: true,
    component: () => import("../views/Detail.vue"),
  },
];

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

<template>
  <div>当前用户ID:{{ id }}</div>
</template>

<script>
export default {
  name: "Detail",
  props: ["id"],
};
</script>

Таким образом, компонент Detail не нужно использовать в маршруте, пока передается атрибут id, его можно применять где угодно.

Поэтому рекомендуется использовать реквизиты для передачи параметров маршрута.

Вложенные маршруты

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

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

Допустим, есть еще и страница входа, ей не нужна верстка, поэтому ей не нужны вложенные маршруты.

Напишите компоненты макета.

<template>
  <div>
    <div>
      <header>header</header>
    </div>
    <div>
      <router-view />
    </div>
    <div>
      <footer>footer</footer>
    </div>
  </div>
</template>

<script>
export default {
  name: "login",
};
</script>

<style>
header {
  width: 100%;
  background: #65b687;
  color: #39495c;
}
footer {
  width: 100%;
  background: #39495c;
  color: #65b687;
}
</style>

Создайте компонент Login.vue.

<template>
  <div>登陆页</div>
</template>

<script>
export default {
  name: "login",
};
</script>

Измените содержимое блока кода шаблона в app.vue.

<template>
  <div id="app">
    <router-view />
  </div>
</template>

Измените конфигурацию маршрутов.

const routes = [
  {
    path: "/login",
    name: "login",
    component: Login,
  },
  {
    path: "/",
    component: Layout,
    children: [
      {
        name: "home",
        path: "",
        component: Home,
      },
      {
        name: "detail",
        path: "detail:id",
        props: true,
        component: () => import("../views/Detail.vue"),
      },
    ],
  },
];

Таким образом, при доступе к http://localhost:8080/login компонент Login будет входить нормально.

При доступе к http://localhost:8080/ сначала будет загружен соответствующий компонент Layout, затем будет загружен компонент Home, а содержимое компонента Layout и компонента Home будет объединено.

При доступе к http://localhost:8080/detail/id он будет загружен так же, как Home, сначала загрузите макет, затем загрузите Detail и передайте идентификатор. Наконец, объедините содержимое двух компонентов.

Программная навигация

Помимо использования router-link для навигации, мы также можем использовать js-код для навигации.

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

Существует 4 часто используемых программных навигационных API. Это $router.push, $router.replace, $router.back и $router.go.

Измените указанные выше три страницы, чтобы использовать эти 4 API.

Целевая страница Перейти на домашнюю страницу, нажав кнопку Landing.

<template>
  <div>
    <div>登陆页</div>
    <button @click="push">登陆</button>
  </div>
</template>

<script>
export default {
  name: "login",
  methods: {
    push() {
      this.$router.push("/");
      // this.$router.push({ name: 'home' })
    },
  },
};
</script>

<style>
button {
  background: #39495c;
  color: #65b687;
  border-radius: 8px;
  padding: 5px 10px;
  border: none;
  outline: none;
}
</style>

Домашняя страница может перейти на страницу сведений о пользователе, или вы можете выйти из системы.Если вы выйдете из системы, вы перейдете на страницу входа, и текущая страница не будет сохранена в истории просмотров браузера.

<template>
  <div class="home">
    <div>Home Page.</div>
    <button @click="goToDetail">查看用户8的资料</button>
    <button @click="exit">退出</button>
  </div>
</template>

<script>
export default {
  name: "Home",
  methods: {
    goToDetail() {
      this.$router.push("/detail/8");
      // this.$router.push({ name: 'detail', params: { id: 8 } })
    },
    exit() {
      // this.$router.replace('/login')
      this.$router.replace({ name: "login" });
    },
  },
};
</script>

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

<template>
  <div>
    <div>当前用户ID:{{ id }}</div>
    <button @click="back">返回</button>
    <button @click="backTwo">回退两页</button>
  </div>
</template>

<script>
export default {
  name: "Detail",
  props: ["id"],
  methods: {
    back() {
      this.$router.back();
    },
    backTwo() {
      this.$router.go(-2);
    },
  },
};
</script>

Использование метода push и метода replace в основном одинаково, а навигация по страницам может быть достигнута путем передачи строки или объекта. Если передается строка, она представляет собой путь к странице. Если объект передан, соответствующий компонент страницы будет найден по атрибуту имени объекта. Если вам нужно передать параметры, вы можете объединить строки или установить свойство params в объекте. Разница между ними заключается в том, что метод replace не записывает историю посещений текущей страницы в браузере, в то время как метод push делает это.

Метод возврата — вернуться на предыдущую страницу, он самый простой в использовании и не требует передачи параметров.

Методу go можно передать параметр типа number, указывающий, следует ли идти вперед или назад. Отрицательное число означает «назад», положительное число означает «вперед», а 0 означает «обновить текущую страницу».

Режим хеширования и режим истории

В Vue Router есть два режима маршрутизации: хэш-режим и режим истории.Режим хеширования будет иметь знак решетки (#) в адресе панели навигации, а режим истории — нет.

Оба режима обрабатываются клиентом, используя JavaScript для прослушивания изменений в маршрутах и ​​отображения различного контента на основе разных URL-адресов. Если вам нужен контент на стороне сервера, используйте для его получения Ajax.

разница в выражении

С эстетической точки зрения режим истории красивее.

URL-адрес шаблона хеша. Будет сопровождаться знаком решетки (#) и знаком вопроса (?) при передаче параметров.

http://localhost:8080/#/user?id=15753140

Ссылка на режим истории.

http://localhost:8080/user/15753140

Однако историю нельзя использовать напрямую и требуется поддержка конфигурации на стороне сервера.

разница в принципе

Режим хеширования основан на якорях и событии onhashchange.

Режим истории основан на History API в HTML5. Объект истории имеет два метода pushState и replaceState. Но следует отметить, что метод pushState должен поддерживаться после IE10. Браузеры до IE10 могут использовать только хеш-режим.

Объект истории также имеет метод push, который изменяет адрес панели навигации и отправляет запрос на сервер. Метод pushState может только изменить адрес панели навигации без отправки запроса на сервер.

Режим истории

История требует поддержки сервера.

Причина в том, что в одностраничном приложении есть только один index.html. В одностраничном приложении проблем не возникнет, если щелкнуть http://localhost:8080/login в обычном режиме. Но когда браузер обновится, будет запрошен сервер, а ресурс, соответствующий этому URL-адресу, не существует на сервере, и будет возвращена ошибка 404.

Поэтому сервер должен быть настроен на возврат index.html для всех запросов, кроме статических ресурсов.

Ниже демонстрируется эффект несоответствия страницы.

Создайте 404.vue в каталоге представлений.

<template>
  <div class="about">
    <h1>404</h1>
  </div>
</template>

Добавьте маршрут 404 в route.

const routes = [
  // other code
  {
    path: "*",
    name: "404",
    component: () => import("../views/404.vue"),
  },
];

Добавьте несуществующую ссылку в Home.vue.

<router-link to="/video">video</router-link>

Затем запустите сервер, войдите на домашнюю страницу, щелкните ссылку на видео, и он перейдет на страницу 404.

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

конфигурация сервера node.js

Сначала используйте Nodejs для разработки сервера.

Создайте папку сервера и инициализируйте проект.

npm init -y

Установите зависимости проекта, используйте здесь экспресс и connect-history-api-fallback.

Express — это известная серверная среда веб-разработки для nodejs.

connect-history-api-fallback — это модуль, который обрабатывает режим истории.

npm i express connect-history-api-fallback

Создайте и напишите файл server.js.

const path = require("path");
// 处理 history 模式的模块
const history = require("connect-history-api-fallback");
const express = require("express");

const app = express();
// 注册处理 history 模式的中间件
app.use(history());
// 注册处理静态资源的中间件
app.use(express.static(path.join(__dirname, "./web")));

app.listen(4000, () => {
  console.log(`
  App running at:
  - Local:   http://localhost:4000/ 
  `);
});

Здесь веб-папка в корневом каталоге серверного проекта задается как корневой путь веб-сайта.

При запуске server.js URL-адрес, запрашивающий http://localhost:4000/, перейдет в веб-папку для поиска соответствующих ресурсов.

Теперь упакуйте исходный проект vue.

Вернувшись в проект vue, запустите команду упаковки.

npm run build

Вы можете получить папку dist.

Скопируйте все из каталога dist в веб-каталог серверного проекта, и развертывание проекта будет завершено.

Затем запустите server.js.

node server.js

Откройте браузер и войдите на страницу сведений (http://localhost:4000/detail/8). Обновите браузер, все нормально.

Если не обращаться с историей, будут проблемы.

попробуй поставитьapp.use(history())Закомментируйте, перезапустите сервер.

Также войдите на страницу сведений, обновите браузер, и вы попадете на страницу 404 по умолчанию экспресс. Причина в том, что при обновлении браузера будет запрашиваться сервер. Сервер не может найти ресурс detail/8 в веб-каталоге. Если обработка истории включена и сервер не может найти detail/8, он вернет index.html, и клиент отобразит компонент в соответствии с текущим путем.

конфигурация сервера nginx

Сначала установите nginx.

Вы можете скачать сжатый пакет nginx с официального сайта nginx.

http://nginx.org/en/download.html

Разархивируйте сжатый пакет в каталог без китайского языка.

Или установите его с помощью некоторых инструментов, таких как brew.

brew install nginx

Команды nginx относительно просты, обычно используются следующие команды.

запускать

nginx

перезагружать

nginx -s reload

остановка

nginx -s stop

Установленный в сжатом пакете, порт nginx по умолчанию — 80. Если 80 не занят, он запустится нормально. После запуска вы можете получить к нему доступ, посетив http://localhost в своем браузере.

Порт nginx по умолчанию, установленный brew, — 8080.

Скопируйте содержимое папки dist проекта vue в папку html в папке nginx. Папка html является папкой по умолчанию для nginx.

После успешного развертывания посетите проект в браузере и обнаружите, что будет та же проблема с обновлением 404.

В это время вам нужно добавить соответствующую конфигурацию в файл конфигурации nginx.

Конфигурация nginx по умолчанию находится в conf/nginx.conf.

Найдите в nginx.conf серверный модуль, который слушает 80, и от него узнайте локацию/местоположение.

Добавьте конфигурацию try_files.

location / {
  root   html;
  index  index.html index.htm;
  # $uri 是 nginx 的变量,就是当前这次请求的路径
  # try files 会尝试在这个路径下寻找资源,如果找不到,会继续朝下一个寻找
  # $uri/ 的意思是在路径目录下寻找 index.html 或 index.htm
  # 最后都找不到的话,返回 index.html
  try_files $uri $uri/ /index.html;
}

После изменения файла конфигурации необходимо перезапустить nginx.

nginx -s reload

После перезагрузки в браузере все работает нормально.

Макет реализации Vue Router

Поскольку реализации режимов истории и хеширования очень похожи, режим истории используется здесь непосредственно для моделирования.

Обзор принципа реализации

Теперь давайте еще раз рассмотрим, как работает vue router.

vue router является маршрутизируемым интерфейсом, при переключении пути браузер определяет, соответствует ли текущий путь и текущий путь загрузочной сборке.

хэш-режим:

  • Содержимое после # в URL-адресе используется в качестве адреса пути.
  • Слушайте событие hashchange
  • Найдите соответствующий компонент и выполните повторный рендеринг в соответствии с текущим адресом маршрутизации.

режим истории:

  • Изменить адресную строку с помощью метода history.pushState()
  • Слушайте событие PopState
  • Найдите соответствующий компонент и выполните повторный рендеринг в соответствии с текущим адресом маршрутизации.

анализировать

Наблюдая за использованием vue router, вы можете быстро понять, как реализован vue router.

Ниже приведен простой процесс использования.

// 注册插件
Vue.use(VueRouter);
// 创建路由对象
const router = new VueRouter({
  routes: [{ name: "home", path: "/", component: homeComponent }],
});
// 创建 Vue 实例,注册 router 对象
new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");

Первый — выполнить Vue.use для регистрации VueRouter.

Метод Vue.use используется для регистрации плагинов, мощность Vue обусловлена ​​его механизмом плагинов. Как и VueRouter, Vuex и некоторые компоненты реализованы с использованием механизма плагинов.

Метод Vue.use может принимать функцию 1 или объект 1. Если это функция, он вызовет функцию напрямую, а если это объект, он вызовет метод установки для объекта. Здесь VueRouter — это объект.

Далее создается экземпляр маршрутизатора, затем VueRouter должен быть конструктором или классом.

В сочетании с приведенным выше анализом мы можем знать, что VueRouter — это класс с методом установки.

Конструктор VueRouter — это объект, а объект параметров построения будет иметь свойство маршрутов, которое записывает информацию о конфигурации маршрута.

Наконец, объект маршрутизатора передается в объект параметра построения, который создает экземпляр Vue.

Класс VueRouter можно описать диаграммой классов UML.

VueRouter UML
VueRouter UML

Диаграмма классов UML состоит из 3 частей.

Верхняя часть — это имя класса, вторая часть — атрибут экземпляра класса, а третья часть — метод класса, где знак плюс (+) представляет метод-прототип, а подчеркивание (_) представляет статический метод.

Атрибуты
  • options: Объект, используемый для хранения объекта, переданного в конструкторе.
  • data: объект с текущим свойством, используемый для записи адреса текущего маршрута. Этот объект является реактивным.
  • routeMap: Объект, используемый для записи соответствия между адресами маршрутов и компонентами.
метод
  • конструктор: метод конструктора.
  • Установка: статический метод, согласованный с механизмом плагина Vue.
  • init: функция инициализации для объединения initRouteMap, initComponents и initEvent.
  • initRouteMap: проанализируйте маршруты в параметрах и установите правила для routeMap.
  • initComponents: создайте компоненты router-link и router-view.
  • initEvent: прослушивание изменений data.current и переключение представлений.

install

Используйте vue cli для создания нового проекта, выберите babel, vue router, eslint в параметрах конфигурации для нашего тестирования.

При использовании Vue.use() сначала будет вызываться установка, поэтому сначала реализуйте установку.

Прежде всего, нам нужно проанализировать, какие вещи должны быть реализованы в установке.

  1. Если Vue уже установил плагин, если да, то нет необходимости устанавливать его снова.
  2. Сохраните конструктор Vue в глобальной переменной. Поскольку методы в конструкторе Vue будут использоваться в более поздних методах экземпляра VueRouter, например, при создании таких компонентов, как router-link и router-view, вам необходимо вызвать Vue.components.
  3. Вставьте объект экземпляра VueRouter, переданный при создании экземпляра Vue, во все экземпляры Vue. Здесь this.$router внедряется в экземпляр Vue.

Создайте каталог vue-router в каталоге src и создайте в нем файл index.js.

let _Vue = null;

export default class VueRouter {
  static install(Vue) {
    // 1. 判断当前插件是否已安装
    if (VueRouter.install.installed) {
      return;
    }
    VueRouter.install.installed = true;
    // 2. 把 Vue 构造函数存储到全局变量中
    _Vue = Vue;
    // 3. 把创建 Vue 实例时传入的 router 对象注入到所有 Vue 实例上
    // 混入
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
        }
      },
    });
  }
}

Первый шаг относительно прост, записывая, подключен плагин или нет.По сравнению с глобальными переменными, лучший способ — добавить установленный атрибут в метод установки самого плагина. Если установлено, вернитесь напрямую. Если он не установлен, установите для него значение true, чтобы продолжить выполнение логики.

Второй шаг очень прост, просто присвойте значение глобальному файлу _Vue.

Третий шаг сложнее, потому что здесь мы не знаем, когда будет вызван новый Vue, поэтому не можем получить объект маршрутизатора в параметрах построения. Это можно решить путем смешивания. Объект, переданный в метод миксина, имеет метод beforeCreate, который является функцией-ловушкой, когда используется новый Vue.this в этой функции указывает на экземпляр Vue, поэтому экземпляр VueRouter может быть внедрен во все экземпляры Vue здесь. Поскольку каждый компонент также является экземпляром Vue, также необходимо различать, является ли он экземпляром Vue или компонентом, иначе логика расширения прототипа будет выполняться много раз. В частности, об этом судят по тому, имеет ли this.$options атрибут маршрутизатора, потому что только экземпляр Vue будет иметь атрибут маршрутизатора, а компонент — нет.

Конструктор

Далее реализуем конструктор Логика конструктора относительно проста.

Создаются три свойства экземпляра. options используется для хранения параметров построения; routerMap — это объект пары «ключ-значение», имя атрибута — адрес маршрутизации, а значение атрибута — компонент; данные — это реагирующий объект с текущим атрибутом для записи текущего адреса маршрутизации. Реактивные объекты можно создавать через _Vue.observable.

export default class VueRouter {
  // other code
  constructor(options) {
    this.options = options;
    this.routeMap = {};
    this.data = _Vue.observable({
      current: "/",
    });
  }
}

initRouteMap

Функция этой функции заключается в преобразовании свойства маршрутов в опциях параметров конструктора в пару ключ-значение и сохранении ее на routeMap.

export default class VueRouter {
  // other code
  initRouteMap() {
    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component;
    });
  }
}

router-link

Затем реализуйте initComponents.Этот метод в основном регистрирует два компонента: router-link и router-view.

Метод initComponents получает в качестве параметра конструктор Vue, цель которого — уменьшить метод и внешние зависимости.

Компонент router-link получит строковый параметр to, который является ссылкой. Сама ссылка на маршрутизатор будет преобразована в тег a, а содержимое ссылки на маршрутизатор будет преобразовано в тег a.

export default class VueRouter {
  // other code
  initComponents(Vue) {
    Vue.component("router-link", {
      props: {
        to: String,
      },
      template: `<a :href="to"><slot></slot></a>`,
    });
  }
}

Создайте функцию инициализации, которая для удобства оборачивает initRouteMap и initComponents.

Затем вызовите метод init при создании экземпляра Vue, чтобы создать компонент router-link.

export default class VueRouter {
  // other code
  static install(Vue) {
    if (VueRouter.install.installed) {
      return;
    }
    VueRouter.install.installed = true;
    _Vue = Vue;
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
          // 在这里调用 init
          this.$options.router.init();
        }
      },
    });
  }

  init() {
    initRouteMap();
    initComponents();
  }
}

Пришло время протестировать.

Замените vue-router в src/router/index.js на наш собственный vue router.

// import VueRouter from 'vue-router'
import VueRouter from "../../vue-router/index";

Стартовый проект.

npm run serve

Открываю браузер, страница пустая, но консоль выдает две ошибки.

Первая ошибка:

vue.runtime.esm.js?2b0e:619 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

Эта ошибка означает, что в настоящее время используется версия Vue для выполнения, а компилятор шаблона недоступен. Шаблоны можно скомпилировать в функции рендеринга с помощью прекомпиляции или можно использовать скомпилированную версию Vue.

Версия сборки Vue:

  • Версия исполнения: шаблон шаблона не поддерживается, его необходимо заранее скомпилировать при упаковке.

  • Полная версия: содержит среду выполнения и компилятор, объем примерно на 10 КБ больше, чем версия среды выполнения, и шаблон преобразуется в функцию рендеринга во время работы программы.

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

Используйте полную версию Vue в VueCLI

Project Vue CLI создан с использованием версии Vue Runtime по умолчанию, потому что она более эффективна.

Если вы хотите изменить конфигурацию проекта Vue Cli, вам необходимо создать файл vue.config.js в корневом каталоге проекта, который использует спецификацию CommonJS для экспорта модуля.

Установите для runtimeCompiler значение true, чтобы использовать полную версию Vue, по умолчанию этот параметр равен false.

module.exports = {
  runtimeCompiler: true,
};

Затем перезапуская проект, первая проблема, с которой я столкнулся, решена.

Однако полная версия Vue будет на 10 КБ больше, и она компилируется во время выполнения, что снижает производительность и не рекомендуется.

Версия среды выполнения Метод рендеринга Vue

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

Когда мы пишем файлы .vue, мы не пишем функции рендеринга без включенного runtimeCompiler. В настоящее время, поскольку веб-пакет, настроенный в Vue Cli, преобразует шаблон в файле vue в функцию рендеринга на этапе компиляции кода и упаковки, то есть предварительной компиляции. И файлы js, которые мы написали, не были предварительно скомпилированы. Таким образом, чтобы использовать функцию рендеринга в среде выполнения Vue.

Сначала удалите vue.config.js.

Измените функцию initComponents.

export default class VueRouter {
  // other code
  initComponents(Vue) {
    Vue.component("router-link", {
      props: {
        to: String,
      },
      // template: `<a :href="to"><slot></slot></a>`
      render(h) {
        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
          },
          [this.$slots.default]
        );
      },
    });
  }
}

Функция рендеринга получает функцию h, роль функции h заключается в создании виртуального DOM, и, наконец, рендеринг возвращает виртуальный DOM.

Существует множество способов использования функции h. Подробную информацию можно найти в официальной документации: https://cn.vuejs.org/v2/guide/render-function.html.

Перезапустил проект, как и ожидалось.

router-view

Компонент Route-View аналогичен компоненту слота, выполняя функцию заполнителя. В соответствии с разными адресами маршрутизации получаются разные компоненты маршрутизации, которые отображаются в позиции router-view.

export default class VueRouter {
  // other code
  initComponents(Vue) {
    // other code
    const self = this;
    Vue.component("router-view", {
      render(h) {
        const component = self.routeMap[self.data.current];
        return h(component);
      },
    });
  }
}

На этом компонент router-view завершен.

Но сейчас пытаюсь нажать на гиперссылку и обнаруживаю, что она нормально не прыгает. Причина в том, что тег a по умолчанию запрашивает сервер, что приводит к обновлению страницы.

Поэтому вам нужно запретить тегу запрашивать сервер по умолчанию и использовать метод histor.pushState для изменения URL-адреса панели навигации.Измененный URL-адрес должен быть сохранен в this.data.current. Потому что this.data — это реактивные данные.

Измените логику компонента router-link.

export default class VueRouter {
  // other code
  initComponents(Vue) {
    // other code
    Vue.component("router-link", {
      props: {
        to: String,
      },
      render(h) {
        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
            on: {
              click: this.clickHandler,
            },
          },
          [this.$slots.default]
        );
      },
      methods: {
        clickHandler(e) {
          history.pushState({}, "", this.to);
          this.$router.data.current = this.to;
          e.preventDefault();
        },
      },
    });
  }
}

Вернитесь к проекту снова и запустите проект. Нажмите на тег, чтобы обновить содержимое страницы в обычном режиме.

initEvent

Хотя все функции были реализованы выше, все же есть небольшая проблема.

Когда вы нажимаете кнопки «вперед» и «назад» в верхнем левом углу браузера, вы только изменяете URL-адрес в адресной строке, а страница не изменяется соответствующим образом.

Решить эту проблему тоже просто.

Идея состоит в том, чтобы прослушать метод popstate и установить в нем значение this.data.current на URL-адрес текущей панели навигации. Поскольку this.data является реактивными данными, при изменении this.data все компоненты, использующие this.data, будут перерисованы.

export default class VueRouter {
  // other code
  init() {
    // other code
    this.initEvent();
  }
  initEvent(Vue) {
    window.addEventListener("popstate", () => {
      this.data.current = window.location.pathname;
    });
  }
}

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

исходный код

На данный момент простая реализация vue router в режиме истории завершена.

Весь исходный код прилагается:

let _Vue = null;

export default class VueRouter {
  static install(Vue) {
    // 1. 判断当前插件是否已经被安装
    if (VueRouter.install.installed) {
      return;
    }
    VueRouter.install.installed = true;
    // 2. 把 Vue 构造函数记录到全局变量
    _Vue = Vue;
    // 3. 把创建的 Vue 实例时所传入的 router 对象注入到 Vue 实例上
    // 混入
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
          this.$options.router.init();
        }
      },
    });
  }

  constructor(options) {
    this.options = options;
    this.routeMap = {};
    this.data = _Vue.observable({
      current: "/",
    });
  }

  init() {
    this.initRouterMap();
    this.initComponents(_Vue);
    this.initEvent();
  }

  initRouterMap() {
    // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routerMap 中
    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component;
    });
  }

  initComponents(Vue) {
    Vue.component("router-link", {
      props: {
        to: String,
      },
      // template: `
      //   <a :href="to">
      //     <slot></slot>
      //   </a>
      // `,
      render(h) {
        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
            on: {
              click: this.clickHandler,
            },
          },
          [this.$slots.default]
        );
      },
      methods: {
        clickHandler(e) {
          history.pushState({}, "", this.to);
          this.$router.data.current = this.to;
          e.preventDefault();
        },
      },
    });

    const self = this;
    Vue.component("router-view", {
      render(h) {
        console.log(self);
        const component = self.routeMap[self.data.current];
        return h(component);
      },
    });
  }

  initEvent() {
    window.addEventListener("popstate", () => {
      this.data.current = window.location.pathname;
    });
  }
}

последние слова

Прошлое позади, и будущее должно быть ярким.

Это не писание лицом к лицу, кроме названия, содержание - мануфактура.

Тем не менее, я собираюсь написать несколько мягких эссе ниже.

Когда есть еще много людей, которые боятся или даже боятся собеседования, и сходят с ума по собеседованию.

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

Вы можете завести друзей-единомышленников и вместе обсудить значение фреймворков и инструментов.

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

Вы также можете читать книги и искать глубокое значение программного обеспечения в книгах.

Короче говоря, есть много-много способов, и путь очень широкий, и все зависит от того, как вы его практикуете.

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

Вы должны знать, что вы можете сделать, а не то, что вы хотите.

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

Не вредите себе из-за денег.

Но без денег, жизнь ты не прав.

В этой статье используетсяmdniceнабор текста