准备分享前端路由的实现方式。
一 、最简单的单页面路由实现方式,从别人博客里找到的代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <ul> <li><a href="#/">turn white</a></li> <li><a href="#/blue">turn blue</a></li> <li><a href="#/green">turn green</a></li> </ul> <script> function Router() { this.routes = {}; this.currentUrl = ''; } console.log(this); Router.prototype.route = function(path, callback) { this.routes[path] = callback || function(){}; }; Router.prototype.refresh = function() { this.currentUrl = location.hash.slice(1) || '/'; this.routes[this.currentUrl](); }; Router.prototype.init = function() { window.addEventListener('load', this.refresh.bind(this), false); window.addEventListener('hashchange', this.refresh.bind(this), false); } window.Router = new Router(); window.Router.init(); var content = document.querySelector('body'); // change Page anything function changeBgColor(color) { content.style.backgroundColor = color; } Router.route('/', function() { changeBgColor('white'); }); Router.route('/blue', function() { changeBgColor('blue'); }); Router.route('/green', function() { changeBgColor('green'); }); </script> <script> </script> </body> </html>
所不理解的是给window添加监听事件时为什么要this.refresh.bind(this).
首先,window.Router初始实例化, window上有了routers和currentUrl;
参考以下继承和实例化的区别:
B.prototype = new A() : B.prototype要找自己属性的时候:先看看自己有没有 --> 看看自己的proto(也就是A.prototype)有没有 --> 一路往上
b = new A(): b找自己属性的时候:先看看自己有没有 --> 看看自己的proto(也就是A.prototype)有没有 --> 一路往上
页面首次加载, Router.proto上找到init , 打印输入后可以发现第一个this是指的Router, 第二个this指的是 window。
还有一个原型链继承和构造函数的区分。
原型链继承:
//父类
var Animal = function(){
//可以在构造函数里面直接设置属性~
this.name = 'animal';
}
//也可以通过prototype
Animal.prototype.say = function(){
console.log('Animal here');
}
//子类
var Dog = function(){
}
Dog.prototype = new Animal();
//改写父类prototype
Dog.prototype.name = 'dog';
//创建实例
var doge = new Dog();
console.log(doge.name) //'dog';
doge.say() //'Animal here
构造函数继承:
//父类
var Animal = function(){
//可以在构造函数里面直接设置属性~
this.name = 'animal';
}
//也可以通过prototype
Animal.prototype.say = function(){
console.log('Animal here');
}
//父类还是一样样的
var Dog = function(){
Animal.call(this);
this.name = 'dog';
}
//创建实例
var doge = new Dog();
console.log(doge.name) //'dog';
doge.say() //error;
没有error这个方法是因为Dog只是借用了Animal的构造方法,Animal的say方法是在prototype上的,没有依靠原型链关系。
二、react-router
npm init 初始化一个项目,建立package.json
安装webpack: npm install webpack --save-dev (安装到项目目录下并且添加到package.json中)
全局安装: npm install webpack -g(全局安装 后续可在命令行中使用webpack)
建立webpack.config.js文件, 先只包含出口和入口,
const path = require('path');
module.exports = {
entry: './src/index.js', //相对路径
output: {
path: path.resolve(__dirname, 'build'), //打包文件的输出路径
filename: 'bundle.js' //打包文件名
}
}
新建入口文件 src/index.js
function hello() {
console.log('hello world');
}
命令窗口执行 webpack, 即可编译成功。此时项目根目录下已经生成好了build/bundle.js。
可以将启动webpack的命令写到package.json中并添加一些参数:
"scripts": {
"start": "webpack --progress --watch --hot"
},
process
是显示打包进程,watch
是监听文件变化,hot
是启动热加载,后续只要执行npm start即可。
配置react项目最重要的两个文件是入口文件(这里是src/index.js)和html模板文件(这里是public/index.html),入口文件是整个项目开始运行的地方,模板文件是构建DOM树的地方。
建立入口文件 public/index.html
0<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My App</title> </head> <body> <div id="root"></div> </body> </html>
安装html-webpack-plugin后补充配置webpack.config.js
npm install html-webpack-plugin --save-dev,
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', //指定模板路径
filename: 'index.html', //指定文件名
})
]
}
重新运行一下:npm start
这时build路径下已经生成好了一个index.html文件,并且这个文件已经引入了bundle.js文件了。
然后开始react项目, 安装react : npm install react react-dom --save-dev 发现此过程中提示refusing to install react under package also named "react", 因为刚开始init的时候命令行里默认执行package中的配置项name值是react, 修改后即可成功。
按照JSX的语法重写src/index.js:
import React, { Component } from 'react'; import ReactDom from 'react-dom'; class App extends Component { render() { return <h1> Hello, world! </h1> } } ReactDom.render( <App />, document.getElementById('root') )
安装babel解析语法:
npm install babel babel-cli babel-loader --save-dev
npm install babel-preset-env babel-preset-react --save-dev
修改webpack.config.js
module.exports = {
entry: './src/index.js', //相对路径
output: {
path: path.resolve(__dirname, 'build'), //打包文件的输出路径
filename: 'bundle.js' //打包文件名
},
module: {
rules: [ //配置加载器
{
test: /.js$/, //配置要处理的文件格式,一般使用正则表达式匹配
loader: 'babel-loader', //使用的加载器名称
query: { //babel的配置参数,可以写在.babelrc文件里也可以写在这里
presets: ['env', 'react']
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
],
}
命令行执行webpack后,遇到问题:
找不到loaders这个配置项,这是因为我使用的webpack是4.x.x了,loaders已被rules替换(2.x.x后全是rules)
替换后遇到问题, 找不到@babel/core,这是因为babel和babel-loader版本不匹配,需将babel-loader回退回低版本(因为我安装的babel是6.x.x):
然后webpack成功:
现在双击打开build/index.html
就可以看到所写的页面内容了。