2019.2.18 一九年的新篇章

     准备分享前端路由的实现方式。

     一 、最简单的单页面路由实现方式,从别人博客里找到的代码如下:

<!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就可以看到所写的页面内容了。

原文地址:https://www.cnblogs.com/yuhanao/p/10399595.html