spa页面路由的基本实现
- hashChange(hash)或者onpopstate(pathname)监听url的改变
- 路由的current的改变,重新获取新的组件渲染
vue-router的源码开发
vue的插件开发
- vue.use()的作用:将传入的方法调用一遍,对象的话就会执行里面的install属性,install方法里面会获取到vue类参数,通过vue.mixin()将方法/属性混入vue的全局实例中;
- 生命周期的方法注入
const plugin = function(vue) {
vue.mixin({
data(){return { }},
methods: {},
breforeCreate: function() { this去操作当前的组件 },
created: function() {},
mounted: function() {},
updated: function() {},
destroyed: function() {},
.............
})
}
- vue内置的方法的使用
1.vue.util: warn、extended、mergOptions、defineReactive(监听data)
vueRouter源码的实现
class historyRouter {
constuctor() {
this.current = null;
}
}
class vueRouter {
constructor(options) {
this.mode = options.mode || hash;
this.routers = options.routers || [];
this.history = new historyRouter();
this.routerMap = this.createMap(this.routes);
this.init();
}
init() {
if(this.mode === 'hash') {
location.hash === '' ? '' : location.hash = '/' ; // 默认跳转到hash模式
window.addEvenListeuener('load', fuction() {
this.history.current = location.hash.slice(1);
});
window.addEvenListener('hashChange', fuction() {
this.history.current = location. pathname;
});
}else {
window.addEvenListeuener('load', fuction() {
this.history.current = location.hash.slice(1);
});
window.addEvenListener('onpopstate', fuction() {
this.history.current = location.history.slice(1);
});
}
}
createMap(router) { // 将传入的数组路由转换为键值对的形式
return router.reduce((memo, current) => {
memo[current.path] = current.component;
retrun emo;
}, {})
}
}
vueRouter.install = function(vue) {
// 监听current变化
vue.mixin({
data: {
beforeCreate: function() { // $option new Vue({ router: [....] })的时候传入
if(this.$options&&this.$options.$router) {
this._root = this; // 将当前组件的this给routerView
this._router = this.$options.router;
// 监听路由当前路径的变化
vue.utils.defineReactive(this, 'current', this._router.history )
}else{
this._root = this.$parent._root;
}
Object.defineProporty(this, ''$router'', { get() { return this._root._router } })
}
}
});
// 渲染控制
vue.component('router-view', {
render(fn){
let current = this._self._root._hitstory.current;
let current = this._self._root._router.routerMap;
return fn(routerMap[current]);
}
})
}
react-router的源码
Router的主体代码
class Router extends React.Component {
static computeRootMatch(pathname) {
return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
}
constructor(props) {
super(props);
this.state = {
location: props.history.location
};
this._isMounted = false; // 是否加载完全
this._pendingLocation = null; // 加载中的路由路径
if (!props.staticContext) { // 开启监听
this.unlisten = props.history.listen(location => {
if (this._isMounted) { // 加载完全后根据监听的location的改变
this.setState({ location });
} else {
this._pendingLocation = location;
}
});
}
}
componentDidMount() {
this._isMounted = true;
if (this._pendingLocation) {
this.setState({ location: this._pendingLocation });
}
}
componentWillUnmount() {
if (this.unlisten) { // 移除监听
this.unlisten();
this._isMounted = true;
this._pendingLocation = null;
}
}
render() {
return (
);
}
}
向所有组件注入路由相关属性
import createContext from "mini-create-react-context";
// 与const {Provider, Consumer} = React.createContext(defaultValue); 效果一样
const createNamedContext = name => {
const context = createContext();
context.displayName = name;
return context;
};
Route的实现
class Route extends React.Component {
render() {
return (
// 注入route共有属性
{context => {
invariant(context, "You should not use outside a ");
const location = this.props.location || context.location;
const match = this.props.computedMatch
? this.props.computedMatch // already computed the match for us
: this.props.path
? matchPath(location.pathname, this.props)
: context.match;
const props = { ...context, location, match };
let { children, component, render } = this.props;
// Preact uses an empty array as children by
// default, so use null if that's the case.
if (Array.isArray(children) && isEmptyChildren(children)) {
children = null;
}
return (
// 重新整理
// 判断是否匹配是否有chidren根据类型渲染
{props.match
? children
? typeof children === "function"
? __DEV__
? evalChildrenDev(children, props, this.props.path)
: children(props)
: children
: component
? React.createElement(component, props)
: render
? render(props)
: null
: typeof children === "function"
? __DEV__
? evalChildrenDev(children, props, this.props.path)
: children(props)
: null}
);
}}
);
}
}