Explorar el Código

Rewrite SPARouter.

Allen hace 8 años
padre
commit
a7077024dc
Se han modificado 5 ficheros con 226 adiciones y 159 borrados
  1. 14 0
      .vscode/launch.json
  2. 1 1
      app.js
  3. 15 3
      public/index.html
  4. 4 0
      public/scr/components/index.js
  5. 192 155
      public/scr/index-dev.js

+ 14 - 0
.vscode/launch.json

@@ -0,0 +1,14 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "node",
+            "request": "launch",
+            "name": "启动程序",
+            "program": "${workspaceFolder}\\app.js"
+        }
+    ]
+}

+ 1 - 1
app.js

@@ -43,4 +43,4 @@ app.use('/v1/index', index);
 app.use('/v1/index/userList', userList);
 app.use('/v1/index/databaseList', databaseList);
 
-app.listen(80);
+app.listen(3000);

+ 15 - 3
public/index.html

@@ -1,14 +1,26 @@
 <!DOCTYPE html>
 <html>
+
 <head>
 	<title>CloudSQL 管理员后台</title>
 	<meta charset="UTF-8">
 	<link rel="stylesheet" href="//cdn.bootcss.com/mdui/0.3.0/css/mdui.min.css">
 	<link href="./css/index.css" rel="stylesheet" type="text/css">
-	<link href="./css/loader.css" rel="stylesheet" type="text/css">
 	<script src="//cdn.bootcss.com/mdui/0.3.0/js/mdui.min.js"></script>
-	<!-- <script type="text/javascript" charset="utf-8" src="http://www.1473.cn/uform.js"></script> -->
 	<script type="text/javascript" src="./scr/index-dev.js"></script>
 </head>
-<body></body>
+
+<body>
+	<main id="router-view"></main>
+</body>
+<script>
+	let routes = [{
+		path: '/index',
+		fileName: 'scr/components/index.js'
+	}],
+		el = document.getElementById('router-view');
+
+	let router = new SPARouter(el, routes, 'hash');
+</script>
+
 </html>

+ 4 - 0
public/scr/components/index.js

@@ -0,0 +1,4 @@
+SPA_RESOLVE_INIT = function ($el, $router) {
+    $el.innerHTML = `<p >当前异步渲染首页${$router.path}</p>`
+    console.log($router)
+}

+ 192 - 155
public/scr/index-dev.js

@@ -1,158 +1,41 @@
-import { DH_NOT_SUITABLE_GENERATOR } from "constants";
+class Utils {
+    getHashRoute() {
+        let hashDetail = window.location.hash.split('?');
+        let hashName = hashDetail[0].split('#')[1];
+        let params = hashDetail[1] ? hashDetail[1].split('&') : [];
+        let query = {};
+        params.map((item) => {
+            let temp = item.split('=');
+            query[temp[0]] = temp[1];
+        });
 
-function Router() {
-    this.router = {}
-    this.beforeFun = null
-    this.afterFun = null
-}
-
-Router.prototype = {
-    init: function () {
-        const windowLoad = handleEvent('load', {
-            onElement: window,
-            withCallback: this.urlChange()
-        })
-        //路由切换
-        const hashChange = handleEvent('hashchange', {
-            onElement: window,
-            withCallback: this.urlChange()
-        })
-        //异步引入js通过回调传递参数
-        window.RESOLVE_INIT = null
-
-    },
-    hashCapture: function () {
-        let hashDeatail = location.hash.split("?"),
-            hashName = hashDeatail[0].split("#")[1], //路由地址
-            params = hashDeatail[1] ? hashDeatail[1].split("&") : [], //参数内容
-            query = {}
-
-        for (let i = 0; i < params.length; i++) {
-            let item = params[i].split("=");
-            query[item[0]] = item[1]
-        }
         return {
             path: hashName,
             query: query
-        }
-    },
-    refresh: function (hash) {
-        if (this.beforeFun) {
-            this.beforeFun({
-                to: {
-                    path: hash.path,
-                    query: hash.query
-                },
-                next: function () {
-                    this.routers[hash.path].callback.call(this, hash)
-                }
-            })
-        } else {
-            this.routers[hash.path].callback.call(this, hash)
-        }
-    },
-    urlChange: function () {
-        let hash = this.hashCapture()
-
-        if (this.routers[hash.path]) {
-            this.refresh(hash)
-        } else {
-            //未注册的hash跳转至首页
-            location.hash = '/index'
-        }
-    },
-    reg: function (path, callback) {
-        path = path.replace(/\s*/g, ""); //过滤空格
-        if (callback && Object.prototype.toString.call(callback) === '[object Function]') {
-            this.routers[path] = {
-                callback: callback, //回调
-                fn: null //存储异步文件状态
-            }
-        } else {
-            console.trace('注册' + path + '地址需要提供正确的的注册回调')
-        }
-    },
-    beforeEach: function (callback) {
-        if (Object.prototype.toString.call(callback) === '[object Function]') {
-            this.beforeFun = callback;
-        } else {
-            console.trace('路由切换前钩子函数不正确')
-        }
-    },
-    afterEach: function (callback) {
-        if (Object.prototype.toString.call(callback) === '[object Function]') {
-            this.afterFun = callback;
-        } else {
-            console.trace('路由切换后回调函数不正确')
-        }
-    },
-    asyncFun: function (file, transition) {
-        // var self = this;
-        if (this.routers[transition.path].fn) {
-            this.afterFun && this.afterFun(transition)
-            this.routers[transition.path].fn(transition)
-        } else {
-            console.log("开始异步下载js文件" + file)
-            let _body = document.getElementsByTagName('body')[0],
-                scriptEle = document.createElement('script')
-
-            scriptEle.type = 'text/javascript';
-            scriptEle.src = file;
-            scriptEle.async = true;
-            RESOLVE_INIT = null;
-            scriptEle.onload = function () {
-                console.log('下载' + file + '完成')
-                this.afterFun && this.afterFun(transition)
-                this.routers[transition.path].fn = RESOLVE_INIT
-                this.routers[transition.path].fn(transition)
-            }
-            _body.appendChild(scriptEle);
-        }
-    },
-    //同步操作
-    syncFun: function (callback, transition) {
-        this.afterFun && this.afterFun(transition)
-        callback && callback(transition)
-    }
-}
-
-/**
- * 事件监听处理类
- * 
- * @param {string} eventName 表示监听事件类型的字符串
- * @param {object} [{ onElement, withCallback, useCapture = false }={}] 监听对象 回调函数 useCapture
- * @param {function} thisArg 
- * @returns function
- */
-function handleEvent(eventName, {
-    onElement,
-    withCallback,
-    useCapture = false
-} = {}, thisArg) {
-    const element = onElement || document.documentElement
-
-    function handler(event) {
-        if (typeof withCallback === 'function') {
-            withCallback.call(thisArg, event)
-        }
+        };
     }
+    getHistoryRoute() {
+        let path = (window.history.state && window.history.state.path) || '';
+        let queryStr = window.location.hash.split('?')[1];
+        let params = queryStr ? queryStr.split('&') : [];
+        let query = {};
+        params.map((item) => {
+            let temp = item.split('=');
+            query[temp[0]] = temp[1];
+        });
 
-    handler.destroy = function () {
-        return element.removeEventListener(eventName, handler, useCapture)
+        return {
+            path: path,
+            query: query
+        };
     }
-
-    element.addEventListener(eventName, handler, useCapture)
-    return handler
-}
-
-Ajax = {
     /**
      * 发送Get请求
      * 
      * @param {!string} url 请求地址
      * @param {?function} next 回调函数
      */
-    get: function (url, next) {
+    ajaxGet(url, next) {
         let xhr = new XMLHttpRequest();
 
         if (url.includes('?')) {
@@ -173,7 +56,7 @@ Ajax = {
             next.call(this, response);
         };
         xhr.send();
-    },
+    }
     /**
      * 发送Post请求
      * 
@@ -181,7 +64,7 @@ Ajax = {
      * @param {?string} data post请求参数
      * @param {?function} next 回调函数
      */
-    post: function (url, data, next) {
+    ajaxPost(url, data, next) {
         let xhr = new XMLHttpRequest();
 
         if (url.includes('?')) {
@@ -203,19 +86,173 @@ Ajax = {
         };
         xhr.send(data);
     }
+    /**
+     * 事件监听处理类
+     * 
+     * @param {string} eventName 表示监听事件类型的字符串
+     * @param {object} [{ onElement, withCallback, useCapture = false }={}] 监听对象 回调函数 useCapture
+     * @param {function} thisArg 
+     * @returns function
+     */
+    handleEvent(eventName, {
+        onElement,
+        withCallback,
+        useCapture = false
+    } = {}, thisArg) {
+        const element = onElement || document.documentElement
+
+        function handler(event) {
+            if (typeof withCallback === 'function') {
+                withCallback.call(thisArg, event)
+            }
+        }
+
+        handler.destroy = function () {
+            return element.removeEventListener(eventName, handler, useCapture)
+        }
+
+        element.addEventListener(eventName, handler, useCapture)
+        return handler
+    }
 }
 
-Util = {
-/*     permissionCheck: function (next) {
-        this.ajax.get('http://admin.cloudsql.1473.cn/v1/index/signStatus', function (response) {
-            if (response.status == 'signedin') {
-                next.call(this);
+/**
+ * declare route: { path: '/xx', fileName: 'xxx', initFunc(){}}
+ *
+ *
+ * @class SPARouter
+ */
+
+class SPARouter {
+    constructor(el, routers, mode) {
+        this.el = el;
+        this.mode = mode || 'hash';
+        this.utils = new Utils();
+        this.currentRoute = {};
+        this.beforeFunc = null;
+        this.afterFunc = null;
+        this.initRouters(routers);
+        this.init();
+    }
+    init() {
+        window.SPA_RESOLVE_INIT = null;
+        this.initEvent();
+    }
+    initRouters(routers) {
+        this.routers = routers.map((item) => {
+            item.$router = this;
+            return item;
+        });
+    }
+    initEvent() {
+        window.addEventListener('load', () => {
+            console.log('load')
+            this.routeUpdate();
+        });
+        if (this.mode === 'history') {
+            window.addEventListener('popstate', (e) => {
+                console.log('popstate')
+                this.routeUpdate();
+            });
+            // 禁用所有a 链接默认跳转事件
+            let self = this;
+            document.addEventListener('click', function (e) {
+                let target = e.target || e.srcElement;
+                if (target.tagName === 'A') {
+                    e.preventDefault();
+                    let href = target.getAttribute('href');
+                    let path = href.split('?')[0];
+                    window.history.pushState({
+                        path: path
+                    }, null, href);
+                    self.routeUpdate();
+                }
+            })
+        } else {
+            window.addEventListener('hashchange', () => {
+                console.log('hashchange')
+                this.routeUpdate();
+            });
+        }
+    }
+    loadComponent() {
+        let self = this;
+        if (typeof (self.currentRoute.fn) === 'function') {
+            self.currentRoute.fn(self.el, self.currentRoute);
+        } else {
+            if (this.currentRoute.fileName) {
+                let _body = document.getElementsByTagName('body')[0];
+                let scriptEle = document.createElement('script');
+                scriptEle.src = self.currentRoute.fileName;
+                scriptEle.async = true;
+                scriptEle.type = 'text/javascript';
+                window.SPA_ROUTE_INIT = null;
+                scriptEle.onload = () => {
+                    self.afterFunc && self.afterFunc(self.currentRoute);
+                    self.currentRoute.fn = window.SPA_RESOLVE_INIT;
+                    self.currentRoute.fn(self.el, self.currentRoute);
+                }
+                _body.appendChild(scriptEle);
+            } else {
+                if (self.currentRoute.initFunc) {
+                    self.currentRoute.initFunc(self.el, self.currentRoute);
+                    self.afterFunc && self.afterFunc(self.currentRoute);
+                } else {
+                    console.trace('该路由定义出错,fileName 和 initFunc 必须定义一个')
+                }
+
+            }
+        }
+
+    }
+    refresh(currentHash) {
+        let self = this;
+        if (self.beforeFunc) {
+            self.beforeFunc({
+                path: self.currentRoute.path,
+                query: self.currentRoute.query
+            }, () => {
+                self.loadComponent();
+            })
+        } else {
+            self.loadComponent();
+        }
+
+    }
+    routeUpdate() {
+        let getLocation = this.mode === 'history' ? this.utils.getHistoryRoute : this.utils.getHashRoute;
+        let currentLocation = getLocation();
+        this.currentRoute.query = currentLocation['query']
+        this.routers.map((item) => {
+            if (item.path === currentLocation.path) {
+                this.currentRoute = item;
+                this.refresh();
+            }
+        });
+        if (!this.currentRoute.path) {
+            if (this.mode === 'history') {
+                window.history.pushState({
+                    path: '/index'
+                }, null, '/index');
+                this.routeUpdate();
             } else {
-                window.location.hash = '/signin';
+                location.hash = '/index';
             }
-        }.bind(this));
-    },
-    tableGenerator: function (params) {
-        
+        }
+    }
+    beforeEach(callback) {
+        if (Object.prototype.toString.call(callback) === '[object Function]') {
+            this.beforeFunc = callback;
+        } else {
+            console.trace('路由切换前钩子函数不正确')
+        }
     }
- */}
+    afterEach(callback) {
+        if (Object.prototype.toString.call(callback) === '[object Function]') {
+            this.afterFunc = callback;
+        } else {
+            console.trace('路由切换后钩子函数不正确')
+        }
+    }
+
+}