Promise的回顾及SPA路由实现

 Promise

        return 在对应的promise的函数中

            在promise里面的then函数(catch函数中)return相当于调用resolve 。 throw new Error相当于调用reject
           
           Promise.resolve('第一个值').then((res) => {
                console.log(res)
                return '第二个值' //resolve
            }).then(res => {
                console.log(res)
            })
            Promise.resolve('第一个值').then((res) => {
                console.log(res)
                throw new Error('异常') //reject
            }).catch(err => {
                console.log(err)
            })

 

        then函数里面传递俩个参数(then和catch里面参数为函数)

          
               Promise.reject()
                .then(function success1 (res) {
                console.log('成功');//抛异常
                }, function fn (e) { //处理错误的函数 不会处理前面的函数抛出的错误
                    console.error('错误') //相当于同级的catch
                })

 

        如果对应的then或者catch里面的参数不是函数那么就会发生值穿透

           
                Promise.resolve('我是值')
                .then(1)
                .then(2)
                .then(3)
                .then(console.log) //===> .then(res=>console.log(res)) 

 

        setImmediate 立即执行(没事做先执行你)

            他也是一个宏任务 而且他这个宏任务只排在setTimeout之前

        nextTick (类似于setTimeout 宏任务 又是一个微任务 (他可以是宏任务也可以微任务))    

            当你没有进行dom操作的时候 (没有进行插入或渲染)他是一个微任务
            反之他就是一个宏任务(也就是说它需要等待dom完成相关操作以后才执行)

路由实现

        路由概念

            前端路由:根据对应的请求地址渲染对应的组件(页面)

                根据BOM里面的history和location对象实现(前端路由分俩种模式 hash模式 history模式)

            后端路由:根据对应的请求地址和请求方式来访问对应的接口(restful风格接口)

        前端路由

            前端路由的俩种实现方式  

            hash模式的原理    

                通过监听location.hash的变化 来控制对应的渲染变化(onhashchange)

            history模式的原理

                通过监听对应的state的变化 来控制对应的渲染变化 (onpopstate)
                pushstate 添加state数据 同时会改变对应的url路径
                replacestate 替换state的数据 同时将对应的路径替换为对应的路径
                onpopstate事件 必须利用history.back history.go history.forward

            单页应用

                前面提到了对应的hash模式或者是history模式都不会进行页面的跳转(不会进行刷新操作)也就是说
                对应的页面不能进行跳转也就意味着对应的页面只有一个。只有一个页面的应用(SPA 单页应用)

            基于单页应用实现路由

            hash模式实现代码

               
                <div id="app">
                    <router-view name="/"></router-view>
                </div>
                <script src="./hash.js"></script>

                
                // 利用hash实现的路由
                class Router {
                    constructor(){
                        //路由配置储存的列表 地址 渲染什么
                        this.routes = []
                    }
                    add(path,commponent){ //添加路由配置 path表示对应的路由路径 commponent表示需要渲染的内容
                        this.routes.push({
                            path,
                            commponent
                        })
                    }
                    listener(el){ //监听函数 监听对应的hash变化的 做对应的处理 el表示你需要渲染的内容
                        window.onhashchange = this.hashChange(el)
                        this.hashChange(el)() //第一次需要调用
                    }
                    hashChange(el){
                        let that = this
                        return function(){
                            // location.hash
                            let hash = location.hash //获取当前的hash值
                            // 把第一个#删除
                            hash = hash.substring(1)
                            // 根据获取的hash值取数组里面匹配出来
                            that.routes.forEach(route=>{
                                if(route.path == hash){ //匹配出来了
                                    // 进行相关的渲染
                                    el.innerHTML = route.commponent()
                                }
                            })
                        }
                    }
                }
                let router = new Router()
                // 先添加对应的地址
                router.add('/',function(){
                    return `<h1>我是主页</h1>`
                })
                router.add('/list',function(){
                    return `<h1>我是列表页</h1>`
                })
                router.add('/user',function(){
                    return `<h1>我是用户页</h1>`
                })
                // 打开页面就加#
                window.onload = ()=>{
                    //获取router-view
                    let view = document.querySelector('router-view')
                    //跟对应的name存在关系
                    let path = view.getAttribute('name')
                    let box = document.createElement('div')
                    document.querySelector('#app').replaceChild(box,view)
                    // 判断是否存在#
                    if(!location.href.includes('#')){
                        location.href += '#/'
                    }
                    //做渲染
                    // 监听调用
                    router.listener(box)
                }

 

            history模式          

               <div id="app">
                    改成a标签
                    <router-link to="/">主页</router-link>
                    <router-link to="/user">用户页</router-link>
                    <router-link to="/list">列表页</router-link>
                    <router-view name="path"></router-view>
                </div>
                <script src="./history.js"></script>
               
                
                //利用history实现的路由
                class Router {
                    constructor() {
                        this.routes = [] //存储对应的路由配置
                        this.callback
                    }
                    add(path, commponent) { //添加的方法
                        this.routes.push({
                            path,
                            commponent
                        })
                    }
                    listener(callback) { //传递一个函数 专门用于渲染
                        this.callback = callback
                        history.pushState('/', '', '/') //第一次进入/
                        this.render()
                        window.onpopstate = () => {
                            this.render()
                        }
                    }
                    render() {
                        let that = this
                        //获取对应的路径地址
                        let path = location.pathname
                        // 比对 拿对应的routes去进行遍历比对
                        this.routes.forEach(route => {
                            if (route.path == path) {
                                //进行渲染
                                that.callback(route.commponent())
                            }
                        })
                    }
                }
                //构建一个路由对象
                let router = new Router()
                router.add('/', () => '<h1>主页</h1>')
                router.add('/user', () => '<h1>用户页</h1>')
                router.add('/list', () => '<h1>列表页</h1>')
                router.listener(renderHtml => {
                    //获取router-view
                    let view = document.querySelector('router-view')
                    view.innerHTML = renderHtml
                })
                //获取所有的router-link 变成a标签
                let links = document.querySelectorAll('router-link')
                //保存所有的创建的a
                let aArr = []
                //读取对应的属性 需要遍历
                Array.from(links).forEach(link => {
                    //获取to属性加给对应的a的href
                    //创建a标签替换对应的router-link
                    let a = document.createElement('a')
                    a.href = link.getAttribute('to')
                    a.innerHTML = link.innerHTML //将link的内容拿出赋值给对应的a
                    document.querySelector('#app').replaceChild(a, link)
                    aArr.push(a)
                })
                //给a添加点击事件
                aArr.forEach(a => {
                    a.onclick = function (e) {
                        e.preventDefault(); //禁止a的默认事件
                        //点击的时候 pushState加东西
                        history.pushState(this.href, '', this.href)
                        //重新渲染
                        router.render()
                    }
                })

 

posted @ 2022-08-29 20:11  一对7  阅读(23)  评论(0编辑  收藏  举报