如何监听 pushState 和 replaceState 的变化呢?
利用自定义事件new Event()
创建这两个事件,并全局监听:
<body>
<button onclick="goPage2()">去page2</button>
<div>Page1</div>
<script>
let count = 0;
function goPage2 () {
history.pushState({
count: count++ }, `bb${
count}`,'page1.html')
console.log(history)
}
// 这个不能监听到 pushState
// window.addEventListener('popstate', function (event) {
// console.log(event)
// })
function createHistoryEvent (type) {
var fn = history[type]
return function () {
// 这里的 arguments 就是调用 pushState 时的三个参数集合
var res = fn.apply(this, arguments)
let e = new Event(type)
e.arguments = arguments
window.dispatchEvent(e)
return res
}
}
history.pushState = createHistoryEvent('pushState')
history.replaceState = createHistoryEvent('replaceState')
window.addEventListener('pushState', function (event) {
// { type: 'pushState', arguments: [...], target: Window, ... }
console.log(event)
})
window.addEventListener('replaceState', function (event) {
console.log(event)
})
</script>
</body>
Vue路由的钩子函数
首页可以控制导航跳转,
beforeEach
,afterEach
等,一般用于页面title
的修改。一些需要登录才能调整页面的重定向功能。
beforeEach
主要有3个参数to
,from
,next
。to
:route
即将进入的目标路由对象。from
:route
当前导航正要离开的路由。next
:function
一定要调用该方法resolve
这个钩子。执行效果依赖next
方法的调用参数。可以控制网页的跳转
函数式组件优势和原理
函数组件的特点
- 函数式组件需要在声明组件是指定
functional:true
- 不需要实例化,所以没有
this
,this
通过render
函数的第二个参数context
来代替 - 没有生命周期钩子函数,不能使用计算属性,
watch
- 不能通过
$emit
对外暴露事件,调用事件只能通过context.listeners.click
的方式调用外部传入的事件 - 因为函数式组件是没有实例化的,所以在外部通过
ref
去引用组件时,实际引用的是HTMLElement
- 函数式组件的
props
可以不用显示声明,所以没有在props
里面声明的属性都会被自动隐式解析为prop
,而普通组件所有未声明的属性都解析到$attrs
里面,并自动挂载到组件根元素上面(可以通过inheritAttrs
属性禁止)
优点
- 由于函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
- 函数式组件结构比较简单,代码结构更清晰
使用场景:
- 一个简单的展示组件,作为容器组件使用 比如
router-view
就是一个函数式组件 - “高阶组件”——用于接收一个组件作为参数,返回一个被包装过的组件
例子
Vue.component('functional',{
// 构造函数产生虚拟节点的
functional:true, // 函数式组件 // data={attrs:{}}
render(h){
return h('div','test')
}
})
const vm = new Vue({
el: '#app'
})
源码相关
// functional component
if (isTrue(Ctor.options.functional)) {
// 带有functional的属性的就是函数式组件
return createFunctionalComponent(Ctor, propsData, data, context, children)
}
// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data.on // 处理事件
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data.on = data.nativeOn // 处理原生事件
// install component management hooks onto the placeholder node
installComponentHooks(data) // 安装组件相关钩子 (函数式组件没有调用此方法,从而性能高于普通组件)
Vue 修饰符有哪些
vue中修饰符分为以下五种
- 表单修饰符
- 事件修饰符
- 鼠标按键修饰符
- 键值修饰符
v-bind
修饰符
1. 表单修饰符
在我们填写表单的时候用得最多的是input
标签,指令用得最多的是v-model
关于表单的修饰符有如下:
lazy
在我们填完信息,光标离开标签的时候,才会将值赋予给value
,也就是在change
事件之后再进行信息同步
<input type="text" v-model.lazy="value">
<p>{
{value}}</p>
trim
自动过滤用户输入的首空格字符,而中间的空格不会过滤
<input type="text" v-model.trim="value">
number
自动将用户的输入值转为数值类型,但如果这个值无法被parseFloat
解析,则会返回原来的值
<input v-model.number="age" type="number">
2. 事件修饰符
事件修饰符是对事件捕获以及目标进行了处理,有如下修饰符
.stop
阻止了事件冒泡,相当于调用了event.stopPropagation
方法
<div @click="shout(2)">
<button @click.stop="shout(1)">ok</button>
</div>
//只输出1
.prevent
阻止了事件的默认行为,相当于调用了event.preventDefault
方法
<form v-on:submit.prevent="onSubmit"></form>
.capture
使用事件捕获模式,使事件触发从包含这个元素的顶层开始往下触发
<div @click.capture="shout(1)">
obj1
<div @click.capture="shout(2)">
obj2
<div @click="shout(3)">
obj3
<div @click="shout(4)">
obj4
</div>
</div>
</div>
</div>
// 输出结构: 1 2 4 3
.self
只当在event.target
是当前元素自身时触发处理函数
<div v-on:click.self="doThat">...</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
v-on:click.prevent.self
会阻止所有的点击,而v-on:click.self.prevent
只会阻止对元素自身的点击
.once
绑定了事件以后只能触发一次,第二次就不会触发
<button @click.once="shout(1)">ok</button>
.passive
告诉浏览器你不想阻止事件的默认行为
在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll
事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll
事件整了一个.lazy
修饰符
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
- 不要把
.passive
和.prevent
一起使用,因为.prevent
将会被忽略,同时浏览器可能会向你展示一个警告。passive
会告诉浏览器你不想阻止事件的默认行为
native
让组件变成像html
内置标签那样监听根元素的原生事件,否则组件上使用v-on
只会监听自定义事件
<my-component v-on:click.native="doSomething"></my-component>
<!-- 使用.native修饰符来操作普通HTML标签是会令事件失效的 -->
3. 鼠标按钮修饰符
鼠标按钮修饰符针对的就是左键、右键、中键点击,有如下:
.left
左键点击.right
右键点击.middle
中键点击
<button @click.left="shout(1)">ok</button>
<button @click.right="shout(1)">ok</button>
<button @click.middle="shout(1)">ok</button>
4. 键盘事件的修饰符
键盘修饰符是用来修饰键盘事件(onkeyup
,onkeydown
)的,有如下:
keyCode
存在很多,但vue为我们提供了别名,分为以下两种:
- 普通键 (
enter
、tab
、delete
、space
、esc
、up
、down
、left
、right
…) - 系统修饰键 (
ctrl
、alt
、meta
、shift
…)
<!-- 只有按键为keyCode的时候才触发 -->
<input type="text" @keyup.keyCode="shout()">
还可以通过以下方式自定义一些全局的键盘码别名
Vue.config.keyCodes.f2 = 113
5. v-bind修饰符
v-bind
修饰符主要是为属性进行操作,用来分别有如下:
- async 能对
props
进行一个双向绑定
//父组件
<comp :myMessage.sync="bar"></comp>
//子组件
this.$emit('update:myMessage',params);
以上这种方法相当于以下的简写
//父亲组件
<comp :myMessage="bar" @update:myMessage="func"></comp>
func(e){
this.bar = e;
}
//子组件js
func2(){
this.$emit('update:myMessage',params);
}
使用async
需要注意以下两点:
- 使用
sync
的时候,子组件传递的事件名格式必须为update:value
,其中value
必须与子组件中props
中声明的名称完全一致 - 注意带有
.sync
修饰符的v-bind
不能和表达式一起使用 - prop 设置自定义标签属性,避免暴露数据,防止污染HTML结构