目录
组件配置项inheritAttrs、组件实例属性$attrs和$listeners
一、vue的使用
vue不兼容低版本IE
vue的基本使用格式
new Vue({
el:'#app',
inheritAttrs : false,//禁用props的Attribute 继承。下文有详细介绍
props:{
row: {
type: Object,
required: true,
// 默认为空对象
default:()=>({})
},
type: {
type: String,
required: true,
// 这里不能访问data中的数据,会报错。因为初始化props在前
default: 'success',
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
},
data () {
//可以定义一些常量
let a = 123
return {
//只有当实例被创建时就已经存在于 data 中的属性才是响应式的。
firstName: 'Do',
lastName:'sfx'
}
},
computed:{
未有变量(){//默认的get
return 值
},
fullName:{
get(){
return this.firstName + " " + this.lastName
},
set(val){//对fullName设置值时被调用
}
}
},
watch:{
已有变量(){},//浅度监听
变量:{
handler(){},
deep:true//深度监听,深度监听一个对象开销比较大
immediate: true //立即执行
},
监听一个对象,比如obj对象,只有改变obj的引用才会触发handler,改变里面的值并不会触发,解决方法是使用deep:true,
但是开销比较大。所以可使用 'obj.a'的方式
'obj.a':{
handler(){},
}
},
beforeCreate:function(){
//创建前
//实例初始化完成
},
created: function(){
// 创建完成后
// 完成数据观测 props data watch methods的运算
},
beforeMount:function(){
//dom挂载前
// render 被执行,未挂载到界面
},
mounted:function(){
//dom挂载前
// 到这一步才可以访问到DOM
//vue实例暴露了一些有用的实例属性与方法
this.$data
},
beforeUpdate:function(){
//更新前
},
updated:function(){
//更新后
},
beforeDestroy:function(){
//销毁前
},
destroyed:function() {
//销毁后
},
activated: function(){
// keep-alive 组件激活时调用如果你使用keep-alive进行缓存, 又希望每次切换组件的时候更新数据,那么更新数据的请求方式必须写在该钩子函数里
},
deactivated:function(){
// keep-alive 组件停用时调用
},
methods:{
formDate(){
//methods函数里面的this直接指向Vue实例
}
},
//调用函数时可传入$event 获得原生event对象
事件修饰符
},
filters:{
formDate(){...},
example(){...}
},
})
- class与style都可以用对象或数组绑定
当在一个自定义组件上使用 class和style
属性时,这些 class和style 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。
-
在 <template> 元素上使用 v-if 条件渲染分组,把
<template>
元素当做不可见的包裹元素,最终的渲染结果将不包含<template>
元素。 注意,v-show
不支持<template>
元素,也不支持v-else
<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
-
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,如果没有key值,它默认用“就地复用”策略。
即如果数据发生了变化或者顺序被改变,Vue不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,只是去更新相应元素的内容节点。
如果设置了key值,每一个节点都会有唯一的身份识别。当数据发生了变化,vue可以前后对比,算出哪些节点是要重复使用或者调整顺序。
- v-for与v-if同时使用,v-for有更高的优先级
v-model
<input v-model="searchText"> 等价于
<input :value="searchText" @input="searchText = $event.target.value" >
在子组件上使用v-model=“form” 等价于
<custom-input :value="searchText" @input="searchText = $event"></custom-input>
为了让它正常工作,这个组件内的 <input> 必须:
将其 value attribute 绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
改变v-model模式
model: {
prop: 'checked',
event: 'change'
},
插槽
作用域问题: 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
- 默认插槽 一个不带
name
的<slot>
出口会带有隐含的名字“default”。 - 具名插槽
- 作用域插槽
<ul>
<li v-for="( item, index ) in items">
//默认插槽
<slot></slot>
//具名插槽
<slot name="toolbar"></slot>
//作用域插槽
<slot name="listItem" :item="item" :index="index"></slot>
//动态插槽名
<template v-slot:[dynamicSlotName]>
...
</template>
</li>
</ul>
<todo-list>
<template v-slot:listItem="slotProps">
<span class="green">{{ slotProps.item }}</span>
</template>
//具名插槽的缩写
//即把 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:
<template #listItem="slotProps">
<span class="green">{{ slotProps.item }}</span>
</template>
</todo-list>
动态组件
组件配置项inheritAttrs、组件实例属性$attrs
和$listeners
2.4.0新增
组件配置项 inheritAttrs : false 禁用 Attribute 继承
以前假如使用子组件时传了a,b,c三个prop,而子组件的props选项只声明了a和b,那么渲染后c将作为html自定义属性显示在子组件的根元素上。
如果不希望这样,可以设置子组件的配置项 inheritAttrs:false,根元素就会干净多了。并不会影响 style
和 class
的绑定。
$attrs就是保存了子组件没有接受父组件的那些属性
v-bind = "obj" // 传入一个对象的所有属性
v-bind = "$attrs"
$listeners
保存了父组件定义的事件
v-on = "$listeners"
VUE事件:
v-on: click 简写 @click
在普通元素上,v-on(@click)监听原生的DOM事件
事件处理的逻辑少,可以直接写在里面 可用$event访问原生事件对象
<input type="text" :value="msg" @input="msg = $event.target.value">
事件处理的逻辑多时可以接受一个方法
<input type="text" :value="msg" @input="handleInput">
一个参数都没传时,该方法的第一个参数是原生event对象;
handleInput(event)
传参时,可以传$event,即原生event对象
<input type="text" :value="msg" @input="handleInput(a,b,$event)">
handleInput(a,b,e)
以上规则不适用与自定义事件
-------------------------------------------------
正常使用:
子组件 this.$emit('fromChild',123,456)
<使用子组件 v-for="(item, index) in 3"
@fromChild="onChild" />
onChild(a,b){} //都可以接收到 //a-> 123 b-> 456
------------------------------------------------
在父组件中通过$event接收子组件$emit传过来的值:
子组件 this.$emit('fromChild',123)
<使用子组件 v-for="(item, index) in 3"
@fromChild="onChild($event, index)" /> $event表示子组件传过来的第一个值:123,又自己传了下标进去
onChild(a,b){} //a: 123 b:对应的index的值
-----------------------------------------------
子组件 this.$emit('fromChild',123,456)
<使用子组件 v-for="(item, index) in 3"
@fromChild="onChild($event, index)" /> $event表示传过来的第一个值:123,接收不到456,被index覆盖了
onChild(a,b){} //a: 123 b: 对应的index的值
------------------------------------------------
想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符
<base-input @focus.native="onFocus"></base-input>
事件修饰符 .stop与 .self的区别 .passive
<div class="outer" @click="log('outer')">
outer
<div class="mider" @click.stop="log('mider')">
mider
<div class="inner" @click="log('inner')">
inner
</div>
</div>
</div>
.stop停止冒泡 :当点击inner的时候,只会打印inner和mider,因为到mider这里就停止向上冒泡了
将.stop改成 .self之后
.self表示点击的元素(event.target)是自身时触发:当点击inner的时候,会打印inner和outer, 因为并没有停止冒泡,所以outer会打印,因为event.target并不等于mider自身,所以不会打印。
.passive 不阻止默认事件,即执行默认方法
.prevent 阻止默认事件
.capture 使用事件捕获,即先执行外部元素的方法,再执行内部的
passive这个修饰符会执行默认方法。你们可能会问,明明默认执行为什么会设置这样一个修饰符呢?
解析:【浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。】
通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。
这里一般用在滚动监听,@scoll,@touchmove 。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent会使滑动卡顿。我们通过passive将内核线程查询跳过,可以大大提升滑动的流畅度。
原文链接:Vue事件修饰符(二).prevent .passive - 简书
<!-- Ctrl + Enter同时按下触发-->
<input type="text" @keyup.ctrl.enter="log('text')">
<!-- Ctrl + 鼠标点击触发-->
<div class="outer" @click.ctrl="log('outer')">outer</div>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
杂乱知识点:
- 在 JavaScript 中对象和数组是通过引用传入子组件的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
- 在beforeDestory中清除定时器。更简易写法如下:
mounted(){ let timer = setInterval(fun,1000) this.$once('hook:beforedestory',()=>{ clearInterval(timer) }) }
- xxxxxxxxxx
工作总结:
- mounted中不能拿到DOM节点 , 要拿到使用v-show
- this.$el 当前页面的DOM
- this.$el.contains(e.target)
- this.noteList[index].disabled = false //页面不会响应 需要this.noteList.splice(index,1,{...item,disabled: false})
- 不缓存页面的一些体现:
不缓存页面的一些体现 1.第一次进这个页面会走mounted,如果重复进这个页面(比如动态路由,只是参数不一样),不会继续走mounted 2.切换到了其他页面,再进这个页面,又重新走mounted
6.组件内的beforeRouteEnter()
组件内的beforeRouteEnter(to, from, next)
1. 好像主页面路由里面才有效
2.跟一个页面有没有缓存没有关系,只要是从其他页面进来就会触发。如果还是这个页面,只是参数不一样,不会触发(比如动态路由)
3.这个钩子函数不能获取到this实例,但可以通过next(),传入回调函数,next(vm=>{
//vm访问组件实例
})
来源:https://segmentfault.com/a/1190000039921701
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
console.log('beforeRouteUpdate 组件内更新守卫');
next();
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
console.log('beforeRouteLeave 组件内离开守卫');
next();
}
7.使用vuex存储用户信息时,刷新页面会数据丢失,建议搭配localStorage。
8.如果path定义的不是动态路由,页面跳转时,使用params传参可以,但是刷新后就没有了。
(因为用params一般是 path定义的是动态路由时,用这个传参来拼接路由的)
所以建议使用query传参
9.动态路由的跳转方式:
{
component: ...,
path: '/board/:id',
name: 'board'
}
//跳转方式1:
this.$router.push({
path: '/board/12'
})
//跳转方式2: 建议
this.$router.push({
name: 'board',
params: { id : 12}
})
10.若线上需要对path进行加密,那么都使用name去跳转。 path加密且存在动态路由的情况,跳转方式用上面提到的动态路由跳转方式2。
11.在路由导航守卫中,router.addRoutes
之后的next()
可能会失效,因为可能next()
的时候路由并没有完全add完成
我们可以通过next(to)
巧妙的避开这个问题。这行代码会重新进入router.beforeEach
这个钩子,这时候再通过next()
来释放钩子,就能确保所有的路由都已经挂在完成了。
12.tab页签切换时,调对应页签组件的接口,不要一次性全部请求。解决方法:
<el-tabs v-model='activeTab'>
<el-tab-pane name='tab-1'>
<组件 v-if='activeTab== 'tab-1'><组件>
</el-tab-pane>
<el-tab-pane name='tab-2'>
<组件 v-if='activeTab== 'tab-2'><组件>
</el-tab-pane>
</el-tabs>
但有一个问题,每次点击这个tab组件都会重新挂载一次,就是tab来回切换的时候会重复请求,这时候我们就可以用到
<keep-alive>
了
keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。 它是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
<el-tabs v-model='activeTab'>
<el-tab-pane name='tab-1'>
<keep-alive>
<组件 v-if='activeTab== 'tab-1'><组件>
</keep-alive>
</el-tab-pane>
<el-tab-pane name='tab-2'>
<keep-alive>
<组件 v-if='activeTab== 'tab-2'><组件>
</keep-alive>
</el-tab-pane>
</el-tabs>