Vue-router

TIP

JSX是一种JS和HTML混合的语法,将组件的结构、数据甚至样式都聚合在一起定义组件

一、简介

  • VueRouter 是一个构造函数,有三种实现方式:hash、history、abstract
  • 特点对比:
    • hash 特点丑 兼容性好 location.hash = 'xx' / window.addEventListener('hashchange')
    • history 漂亮像正常路径一样,但是需要服务端支持 history-fallback pushState / window。addEventListener('popstate')
  • 前端路由的核心:根据路径,去渲染对应的组件

一、install原理

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
});

new Vue({
  router, // 创建实例时提供router属性 表示初始化路由
  render: h => h(App),
}).$mount('#app')

// 1. 初始化调用Vue.use注入路由构造函数的时候,会默认调用Vue.install方法
Vue.use(VueRouter,{});

// 源码
Vue.use = function (plugin, options) {
	// this为大Vue构造函数
	plugin.install(this, options)
}

// 2. VueRouter的类上挂载一个install方法
export default class VueRouter{
 
}
VueRouter.install = install;

// 3. install作用: 
// 		a.存储Vue实例到全局变量中 
// 		b.调用Vue.mixin方法,在beforeCreate的声明周期钩子中混入router实例
//      c.调用vuerouter的init方法进行初始化
export let _Vue;
export function install(Vue, options) {
	_Vue = Vue;
    Vue.mixin({
        beforeCreate() { // 每个组件都会执行beforecreate方法
            // 获取到每个人的实例,给实例添加属性
            if (this.$options.router) {
                this._routerRoot = this; // 把根实例挂在到_routerRoot上
                this._router = this.$options.router;
                //  this._router 路由的实例 new VueRouter
                this._router.init(this);
                // global-api 里面定义了这个方法 

                Vue.util.defineReactive(this, '_route', this._router.history.current)
            } else {
                // this._routerRoot指向了当前 根组件的实例
                // iifecycleMixin  构建父子关系
                this._routerRoot = this.$parent && this.$parent._routerRoot
                // this._routerRoot._router
            }
        }
        // 根_routerRoot => 父亲_routerRoot => 儿子_routerRoot => 孙子_routerRoot
    });

    Object.defineProperty(Vue.prototype,'$route',{
       get(){
          return this._routerRoot._route // current 对象里面放的都是属性 path matched
       }
    });
    Object.defineProperty(Vue.prototype,'$router',{
      get(){
         // router.history.push()
         return this._routerRoot._router; // addRoute match 
      }
   });
   Vue.component('router-link',RouterLink);
   Vue.component('router-view',RouterView)
}
  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化
  • 它是类型安全的,在编译过程中就能发现错误
  • 使用 JSX 编写模板更加简单快速

二、核心逻辑

四、router-view

五、钩子原理

1 独立文件

ReactDOM.render(
  <h1>hello</h1>,
  document.getElementById('root')
);

2 表达式

  • 可以任意地在 JSX 当中使用 JavaScript 表达式,在 JSX 当中的表达式要包含在大括号里
let title = 'hello';
ReactDOM.render(
  <h1>{title}</h1>,
  document.getElementById('root')
);

3 属性和样式

  • 在JSX中属性不能包含关键字,像class需要写成className,for需要写成htmlFor,并且属性名需要采用驼峰命名法
ReactDOM.render(
  <h1 className="title" style={{ color: 'red' }} htmlFor="username">Hello</h1>,
  document.getElementById('root')
);

4 if条件

function greeting(name){
   if(name){
      return <h1>hello {name}</h1>
   }else{
     return <h1>hello stranger</h1>
   }
}
let element = greeting('hello');
ReactDOM.render(
  element,
  document.getElementById('root')
);

5 for循环

let names = ['张三','李四','王五'];
//把一个字符串的数组映射为一个li的数组
let lis = names.map(name => <li>{name}</li>);
ReactDOM.render(
  <ul>{lis}</ul>,
  document.getElementById('root')
);

6 数组默认展开

var arr = [
  <h1>张三</h1>,
  <h2>李四</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('root')
);

7 注释

ReactDOM.render(
  <div>
	{/*注释...*/}
	<h1>张三</h1>
  </div>,
  document.getElementById('root')
);

三、执行过程

  1. 写代码为JSX:<h1>hello</h1>
  2. 打包的时候,会调用webpack中的babel-loader把JSX写法转换成JS写法 React.createElement
  3. 在浏览器里执行createElement,得到虚拟DOM,也就是React元素,它是一个普通的JS对象,描述了你在界面上想看到的DOM元素的样式
  4. 把React元素(虚拟DOM)给了ReactDOM.render方法,render会把虚拟DOM转成真实DOM,并且插入页面