【Vue-router】hash模式和history模式

经过前一段时间磕路由的官方文档及做了一些实验,我终于是个废人了。现在对路由的了解,可能是由之前的‘人畜不分’阶段变成了‘这是个会做什么东西的人’阶段。前路漫漫,继续磕吧!刚嘛嘚!!
现在单页应用盛行,前端路由也成为目前各个框架的基础标配,然后就搞得路由也是一大难题,越来越复杂,对于我这个小菜鸡来说,啃这个骨头,还是挺费头发的。

今天总结两个牛掰哄哄的两个框架(React和Vue)的hash模式和history模式。

先介绍一下,前端路由、hash模式及history模式到底是什么玩意儿
前端路由 :在服务端,就是url和处理函数之间的映射关系。在web前端单页应用中,就是url和UI之间的映射关系,在无需刷新页面的情况下,url变化会引起UI更新。

那么要实现前端路由,就要搞清楚怎么去检测url是否变化?url变化的时候,怎么实现页面不刷新?

接下来就有意思了,该hash和history出场了
hash模式:使用hash模式,在url中会出现"#",那么hash值就是url中从"#"号开始到结束的部分(常用做锚点在页面进行导航),改变url中hash部分就不会引起页面刷新。hash模式是使用hashchange事件监听url的变化的。

那么我们怎么去改变url去触发hashchange事件呢?
1,通过标签改变url;2,通过浏览器的前进后退改变url;3,通过window.location改变url。(目前也就这3种方式可以改变url。)

history模式:相较于url中多一个“#”看起来丑丑的hash模式,history模式更优雅一点。history模式提供pushState和replaceState两种方发去改变url的path部分,同样,页面是不会刷新的。
history模式监听url变化稍稍复杂一 nei nei,但也是可以实现滴。
history 提供popstate 事件:通过浏览器前进后退改变 URL 时会触发 popstate 事件,but,通过pushState/replaceState或标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。

那么接下来,就是嗨皮的时候了—React实现前端路由!

直接上代码!
基于hash模式的前端路由实现!

<HashRouter>
    <ul>
      <li>
        <Link to="/home">home</Link>
      </li>
      <li>
        <Link to="/about">about</Link>
      </li>
    </ul>

    <Route path="/home" render={() => <h2>Home</h2>} />
    <Route path="/about" render={() => <h2>About</h2>} />
  </HashRouter>

HashRouter的实现

export default class HashRouter extends React.Component {
  state = {
    currentPath: utils.extractHashPath(window.location.href)
  };

  onHashChange = e => {
    const currentPath = utils.extractHashPath(e.newURL);
    console.log("onHashChange:", currentPath);
    this.setState({ currentPath });
  };

  componentDidMount() {
    window.addEventListener("hashchange", this.onHashChange);
  }

  componentWillUnmount() {
    window.removeEventListener("hashchange", this.onHashChange);
  }

  render() {
    return (
      
        {this.props.children}
      
    );
  }
}

Router的实现

export default ({ path, rander }) => (

	{({currentPath}) => currentPath === path && render()}
	
);

基于history模式的前端路由实现

 <HistoryRouter>
    <ul>
      <li>
        <Link to="/home">home</Link>
      </li>
      <li>
        <Link to="/about">about</Link>
      </li>
    </ul>

    <Route path="/home" render={() => <h2>Home</h2>} />
    <Route path="/about" render={() => <h2>About</h2>} />
  </HistoryRouter>

HistoryRouter 实现:

export default class HistoryRouter extends React.Component {
	state = {
		currentPath: utils.extractUrlPath(window.location.href)
	};

	onPopState = e => {
		const currentPath = utils.extractUrlPath(window.location.href);
		console.log('onPopState', currentPath);
		this.setState({ currentPath });
	};

	componentDidMount() {
		window.addEventListener('popState', this.onPopState);
	}

	componentWillMount() {
		window.removeEventListener('popState', this.onPopState);
	}

	render() {
	 
	 	return (
	 	
			{this.props.children}
			
		);
	}
}

Route实现

export default ({ path, render }) => (
  
    {({currentPath}) => currentPath === path && render()}
  
);

Link 实现:

export default ({ to, ...props }) => (
  
    {({ onPopState }) => (
              href=""
        {...props}
        onClick={e => {
          e.preventDefault();
          window.history.pushState(null, "", to);
          onPopState();
        }}
      />
    )}
  
);

呼呼。。。React框架 Over。爬起来继续肝Vue框架,Begin!!!

Vue实现前端路由

持续暴击,直接上代码
基于hash模式的前端路由实现!

     <div>
      <ul>
        <li><router-link to="/home">home</router-link></li>
        <li><router-link to="/about">about</router-link></li>
      </ul>
      <router-view></router-view>
    </div>
const routes = {
  '/home': {
    template: '<h2>Home</h2>'
  },
  '/about': {
    template: '<h2>About</h2>'
  }
}

const app = new Vue({
  el: '.vue.hash',
  components: {
    'router-view': RouterView,
    'router-link': RouterLink
  },
  beforeCreate () {
    this.$routes = routes
  }
})

router-view 实现:

<template>
  <component :is="routeView" />
</template>

<script>
import utils from '~/utils.js'
export default {
  data () {
    return {
      routeView: null
    }
  },
  created () {
    this.boundHashChange = this.onHashChange.bind(this)
  },
  beforeMount () {
    window.addEventListener('hashchange', this.boundHashChange)
  },
  mounted () {
    this.onHashChange()
  },
  beforeDestroy() {
    window.removeEventListener('hashchange', this.boundHashChange)
  },
  methods: {
    onHashChange () {
      const path = utils.extractHashPath(window.location.href)
      this.routeView = this.$root.$routes[path] || null
      console.log('vue:hashchange:', path)
    }
  }
}
</script>

router-link 实现:

<template>
  <a @click.prevent="onClick" href=''><slot></slot></a>
</template>

<script>
export default {
  props: {
    to: String
  },
  methods: {
    onClick () {
      window.location.hash = '#' + this.to
    }
  }
}
</script>

基于history模式的前端路由实现

	<div>
      <ul>
        <li><router-link to="/home">home</router-link></li>
        <li><router-link to="/about">about</router-link></li>
      </ul>
      <router-view></router-view>
    </div>
const routes = {
  '/home': {
    template: '<h2>Home</h2>'
  },
  '/about': {
    template: '<h2>About</h2>'
  }
}

const app = new Vue({
  el: '.vue.history',
  components: {
    'router-view': RouterView,
    'router-link': RouterLink
  },
  created () {
    this.$routes = routes
    this.boundPopState = this.onPopState.bind(this)
  },
  beforeMount () {
    window.addEventListener('popstate', this.boundPopState) 
  },
  beforeDestroy () {
    window.removeEventListener('popstate', this.boundPopState) 
  },
  methods: {
    onPopState (...args) {
      this.$emit('popstate', ...args)
    }
  }
})

router-view 实现:

<template>
  <component :is="routeView" />
</template>

<script>
import utils from '~/utils.js'
export default {
  data () {
    return {
      routeView: null
    }
  },
  created () {
    this.boundPopState = this.onPopState.bind(this)
  },
  beforeMount () {
    this.$root.$on('popstate', this.boundPopState)
  },
  beforeDestroy() {
    this.$root.$off('popstate', this.boundPopState)
  },
  methods: {
    onPopState (e) {
      const path = utils.extractUrlPath(window.location.href)
      this.routeView = this.$root.$routes[path] || null
      console.log('[Vue] popstate:', path)
    }
  }
}
</script>

router-link 实现:

<template>
  <a @click.prevent="onClick" href=''><slot></slot></a>
</template>

<script>
export default {
  props: {
    to: String
  },
  methods: {
    onClick () {
      history.pushState(null, '', this.to)
      this.$root.$emit('popstate')
    }
  }
}
</script>

OVER!!!!人已废,头已秃!!一定要动手自己搞一遍,对,没错,不能我一个人秃。
在这里插入图片描述
参考网址:
https://router.vuejs.org/zh/guide/
下面的文章需要复制,微信或者QQ打开
https://mp.weixin.qq.com/s?src=12&timestamp=1610411470&signature=3EMThyz-2dQgllJuVZe8JMOLwaZ7wUUOf444ES23KSngX1fUjNbeRVGa5JBmUybjrNscncAuqsY9yeOeDMCjFcrq39NrDE659203AXKpWHXzpD-jhcqr9*0EpUc-3Mwy&ver=2823&article_id=1336672358&rowkey=6845f84f53d56314&_wv=2147532945&ref=kandian&_pflag=24

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值