Vue 生命周期
Vue 语法和概念
- 差值表达式
- 指令(14个)
- 计算属性和侦听器
- class 和 style 绑定
- 条件渲染和列表渲染
- 表单输入渲染
- 组件
- 插槽
- 插件
- 混入 mixin
- 深入响应式原理
- 不同构建版本的 vue
vue router 原理实现
基本使用
import Vue from "vue";
import VueRouter from "vue-router";
import Index from "./views/Index.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Index",
component: Index,
},
{
path: "/blog",
name: "Blog",
// route level code-splitting
// lazy-loaded
component: import(/* webpackChunkName: "blog" */'./views/Blog.vue'),
}
];
const router = new VueRouter({
routes
});
new Vue({
router,
el: "#app"
});
// Index.vue
<template>
<router-view></router-view>
</template>
router 会给组件注入 $route 和 $router 两个属性。
动态路由匹配
const routes = [
{
path: "/blog/:id",
name: "blog",
// 路由参数 id 会传入组件中
props: true,
component: Blog
}
]
嵌套路由
const routes = [
{
path: "/",
component: Layout,
children: [
{
path:"",
name:"index",
component: Index
}
]
}
]
Blog.vue
<script>
export default {
name: "blog",
props: ["id"]
}
</script>
编程式导航
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
Hash 模式和 History 模式的区别
- Hash 模式是基于锚点,以及 onhashchange 事件
- History 模式是基于 html5 中的
historyAPI- history.pushState() IE10 以后才支持
- history.replaceState()
History 模式的使用
- History 需要服务器的支持 history 模式下, 如果浏览器刷新,会向服务器发起请求,如果服务器没有配置的话,就可能返回 404。
History 模式 - nodejs
const path = require("path")
const history = require("connect-history-api-fallback")
const express = require("express");
const app = express();
app.use(history)
app.use(express.static(path.join(__dirname, "./public"));
app.listen(3000, () => {
console.log("服务器开启,端口: 3000")
})
History 模式 - nginx
start nginx
nginx -s reload
nginx -s stop
http {
location / {
root html;
index index.html index.htm
try_files $uri $uri/ /index.html
}
}
VueRouter History 模式下的实现原理
VueRouter 类图
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 实例时传入的 routes 对象注入到 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.createRouteMap();
this.initComponents(_Vue);
this.initEvent();
}
createRouteMap() {
// 遍历所有的路由规则, 把路由规则解析成键值对的形式 存储到 routeMap 中
this.options.routes.forEach((route) => {
this.routeMap[router.path] = router.component;
});
}
initComponents(Vue) {
const self = this;
Vue.component("router-link", {
props: {
to: String,
},
// runtime 版本的 vue 不支持 template 模版
// template: '<a :href="to"><slot></slot></a>',
render(h) {
return h(
"a",
{
attrs: {
href: this.to,
},
on: {
click: this.clickHandler,
},
},
[this.$slote.default]
);
},
methods: {
clickHandler(e) {
history.pushState({}, "", this.to);
// 修改后会触发组件的重新渲染
this.$router.data.current = this.to;
e.prevenDefault();
},
},
});
Vue.component("router-view", {
render(h) {
// 当前路由对应的组件
const component = self.routeMap[self.data.current];
return h(component);
},
});
}
initEvent() {
// 前进 后退,历史记录被激活时,会触发 popstate 事件
window.addEventListener("popstate", () => {
this.data.current = window.location.pathname;
});
}
}