手写vue-router---hash模式
手写前提准备---- 什么是hash
原理就是网页的
锚点
关于锚点
的使用:
一 :锚点的几种写法:
<a href = "#num-1">锚点1</a>
+<div id = 'num-1'></div>
即<a href> + <div id>
(常用)<a href = "#num-1">锚点1</a>
+<a name = 'num-1'></a>
即<a href> + <a name>
(不常用,后者只能写<a>
,限制了一些情况)<div onclick="testFn()">锚点1</div>
+<div id = 'num-1'></div>
这种方式最常用,没有限制。
// 二:锚点写法三 的 testfn 写法
// 1. window.location.hash这个属性可读可写。
function testFn(){
// 写这个以后,就不用写上面那些了。
location.hash = 'num-5'
// 滚动到指定的位置
document.getElementById("num-5").scrollIntoView();
}
// 三: 关于锚点需要知道的函数
// 2. 当#值发生变化时,就会触发这个事件
window.addEventListener('hashchange',function(e){
console.log(e);;
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test-1</title>
</head>
<body>
<p><a href="#num-4">锚点4</a></p>
<p><div onclick="testFn()">锚点5</div></p>
<div id = 'num-1'>
<div> 锚点1content </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content <br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br></div>
</div>
<div id = 'num-2'>
<div> 锚点2content </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content <br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br></div>
</div>
<div id = 'num-3'>
<div> 锚点3content </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content <br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br></div>
</div>
<div id = 'num-4'>
<div> 锚点4content </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content <br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br></div>
</div>
<div id = 'num-5'>
<div> 锚点5content </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br> </div>
<div> 锚点content <br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br>锚点content<br></div>
</div>
<script>
// 当#值发生变化时,就会触发这个事件
window.addEventListener('hashchange',function(e){
console.log(e);;
})
// 2. window.location.hash这个属性可读可写。
function testFn(){
// 写这个以后,就不用写上面那些了。
console.log('1111111111111')
location.hash = 'num-5'
document.getElementById("num-5").scrollIntoView();
}
</script>
</body>
</html>
我们发散一下思维:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>App.vue</title>
</head>
<body>
<router-link :to='num-5'></router-link>
可以看成=======>
<p><div onclick="testFn()">锚点5</div></p> 或者
<p><a href="#num-5">锚点4</a></p>
<div id = 'num-1'>
<router-view/>
可以看成=======>
<div> 页面一 </div>
</div>
<div id = 'num-2'>
<router-view/>
可以看成=======>
<div> 页面二 </div>
</div>
<div id = 'num-3'>
<router-view/>
可以看成=======>
<div> 页面三 </div>
</div>
<div id = 'num-4'>
<router-view/>
可以看成=======>
<div> 页面四 </div>
</div>
<div id = 'num-5'>
<router-view/>
可以看成=======>
<div> 页面五 </div>
</div>
<script>
// 当#值发生变化时,就会触发这个事件
window.addEventListener('hashchange',function(e){
console.log(e);;
})
// 2. window.location.hash这个属性可读可写。
function testFn(){
// 写这个以后,就不用写上面那些了。
console.log('1111111111111')
location.hash = 'num-5'
document.getElementById("num-5").scrollIntoView();
}
</script>
</body>
</html>
手写前提准备---- Render函数中createElement()函数的参数
第一个参数:必填
可选类型:1、string:html标签
2、object:一个含有数据选项的对象
3、function:返回一个含有数据选项的对象
Vue.component('child', {
render: function (createElement) {
//string:html标签
return createElement('h1')
//object:一个含有数据选项的对象
return createElement({
template: '<div>谈笑风生</div>'
})
//function:返回一个含有数据选项的对象
var domFun = function () {
return {
template: `<div>谈笑风生</div>`
}
}
return createElement(domFun())
}
})
第二个参数是数据对象。只能是object
class
style
attrs
domProps
props
on
nativeOn
directives
scopedSlots
slot
key
ref
Vue.component('child', {
props: ['level'],
render: function (createElement) {
return createElement('div', {
class: {
foo: true,
baz: false
},
style: {
height: '34px',
background: 'orange',
fontSize: '16px'
},
//正常的html特性(除了class和style)
attrs: {
id: 'foo',
title: 'baz'
},
//用来写原生的DOM属性
domProps: {
innerHTML: '<span style="color:blue;font-size:24px">江心比心</span>'
}
})
}
})
第三个参数-代表子节点
类型:String|Array
Vue.component('child', {
props: ['level'],
render: function (createElement) {
return createElement('div', [
createElement('h1', '我是大标题'),
createElement('h2', '我是二标题'),
createElement('h3', '我是三标题')
])
}
})
手写vue-router
let Vue
class myRouter {
constructor(options = {}) {
// 定义响应式数据
Vue.util.defineReactive(this, 'current', '/')
this.routers = options.routers //传入的路由表
this.mode = 'hash' //路由模式
this.init()//初始化函数
}
init() {
if (this.mode === 'hash') {
//监听网页初始化,网页加载完成以后,加载第一个页面
window.addEventListener('load', () => {
location.hash = '/'
this.current = location.hash.slice(1)
})
//因为拿到的哈希时带#号的,而用户传入的路由表是不带#号的,所以要去掉#号
window.addEventListener('hashchange', () => {
this.current = location.hash.slice(1)
})
}
}
}
const install = function (vue) {
/**
需要mixin的原因是每个组件都能用 this.$router。
使用混入后,各个页面都可以用了
*/
Vue.mixin({
beforeCreate() {
// 判断是不是根组件
//这里为挂载到构造函数的原型对象上
if (this.$options && this.$options.router) {
Vue.prototype.$router = this.$options.router
}
},
})
//注册全局组件 router-link router-view
//Vue.component函数创建一个组件,第一个参数为组件名称,第二个参数为组件的配置项。
Vue.component('router-link', {
data() {
return {
name: 'router-link'
}
},
props: {
to: {
type: String,
require: true//表示必传
}
},
methods:{
pushUrl(e){
if (this.$router.mode == 'hash') {
location.hash = this.to
}
e.preventDefault()
}
},
render(createElement) {
/**
* createElement函数也就是h函数,用于创建dom。第一个参数为创建的dom名称,即标签名
* 第二个参数为一个配置项
*/
return createElement('a', {
attrs: {
href:this.to,
},
on:{
click:this.pushUrl
}
}, this.$slots.default[0].text)
}
})
Vue.component('router-view', {
render(createElement) {
// current必须是响应式的才会在发生变化的时候触发render函数
let current = this.$router.current //获取当前路由
let routers = this.$router.routers
// 筛选,筛选完成以后进行渲染
let component = routers.find(d => d.path === current)
return createElement(component.component)
}
})
}
export default {
myRouter,
install
}