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() } })