实例属性
vm.$parent
用来访问组件实例的父实例
<div id="app2">
<say-hello></say-hello>
<my-name :name="username"></my-name>
</div>
<script>
Vue.component("sayHello",{
template:"<h2>Hello ${this.$parent.username} !</h2>", //访问父实例(app2)数据this.$parent
delimiters:['${',"}"] //【1】修改插值语法delimiters
});
var app2 = new Vue({
el:"#app2",
data:{
month:"September",
username:"Lily" // 原来是Lily
},
components:{
"myName":{
template:`<div><p>My name is {{ name }} !
This month is {{ this.$parent.month }} .</p>
<button @click="changeName">changeName</button></div>`, //访问父实例(app2)数据this.$parent
props:["name"],
methods:{
changeName:function () {
// 【2】更改父组件的数据,this.$parent为父组件实例
// this为当前实例
this.$parent.username = "Jack";
}
}
}
}
});
</script>
$root
用来访问组件实例的跟实例
vm.$children
当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。
vm.$data
Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象属性的访问。
vm.$props
当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问
vm.$el
用来挂载当前组件实例的dom元素
this.$refs.scroll.$el.style ...
// 访问组件实例的dom元素
vm.$refs
一个对象,持有注册过 ref
特性 的所有 DOM
元素和组件实例
。
vm.$options
获取vue实例选项
new Vue({
customOption: 'foo',
created: function () {
console.log(this.$options.customOption) // => 'foo'
}
})
vm.$slots
用来访问被插槽分发的内容。每个具名插槽 有其相应的属性 (例如:slot="foo"
中的内容将会在 vm.$slots.foo
中被找到)。default
属性包括了所有没有被包含在具名插槽中的节点。
在使用渲染函数书写一个组件时,访问 vm.$slots
最有帮助。
vm.$attrs
包含了父作用域中不作为 prop
被识别 (且获取) 的特性绑定 (class 和 style 除外)。
当一个组件没有声明任何 prop
时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。
这是官网给出的,有点绕,我们还是从例子来看吧
<template>
<div class="home">
<mytest :title="title" :massgae="massgae"></mytest>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
title:'title1111',
massgae:'message111'
}
},
components:{
'mytest':{
template:`<div>这是个h1标题{{title}}</div>`,
props:['title'],
// 【1】 这里只注册了一个
data(){
return{
mag:'111'
}
},
created:function(){
// 【2】 打印出来是 {message: message111}
console.log(this.$attrs)//注意这里
}
}
}
}
</script>
我们看到:组件内未被注册的属性将作为普通html元素属性被渲染,如果想让属性能够向下传递,即使prop组件没有被使用,你也需要在组件上注册。
在Vue2.4.0
,可以在组件定义中添加inheritAttrs:false
,组件将不会把未被注册的props
呈现为普通的HTML属性。但是在组件里我们可以通过其$attrs可以获取到没有使用的注册属性,如果需要,我们在这也可以往下继续传递。
components:{
'mytest':{
template:`<div>这是个h1标题{{title}}</div>`,
props:['title'],
inheritAttrs: false,
// 【3】 这里为 inheritAttrs = false
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意这里
}
}
vm.$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
场景
A 组件与 B 组件之间的通信: (父子组件)
往往数据在不需要全局的情况而仅仅是父子组件通信时,使用第一种方式即可满足。
1. A to B 通过props的方式向子组件传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现
2. 通过设置全局Vuex共享状态,通过 computed 计算属性和 commit mutation的方式实现数据的获取和更新,以达到父子组件通信的目的。
3. Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递。
A 组件与 C 组件之间的通信: (跨多级的组件嵌套关系)
1. 借助 B 组件的中转,从上到下props依次传递,从下至上,$emit事件的传递,达到跨级组件通信的效果
2. 借助Vuex的全局状态共享
3. Vue Event Bus,使用Vue的实例,实现事件的监听和发布,实现组件之间的传递。
- 第一种通过props和$emit的方式,使得组件之间的业务逻辑臃肿不堪,B组件在其中仅仅充当的是一个中转站的作用。
- 使用第二种 Vuex的方式,某些情况下似乎又有点大材小用的意味,(仅仅是想实现组件之间的一个数据传递,并非数据共享的概念)
- 第三种情况的使用在实际的项目操作中发现,如不能实现很好的事件监听与发布的管理,往往容易导致数据流的混乱,在多人协作的项目中,不利于项目的维护。
$attrs
以及$listeners
的出现解决的就是第一种情况的问题
// app.vue
<template>
<div id="app">
<child1
:p-child1="child1" // 【1】 传第一个值
:p-child2="child2" // 【2】 传第二个值
v-on:test1="onTest1" //此处监听了两个事件,可以在B组件或者C组件中直接触发
v-on:test2="onTest2">
</child1>
</div>
</template>
<script>
import Child1 from "./Child1.vue";
export default {
data() {
return {};
},
components: { Child1 },
methods: {
onTest1() {
// 子组件触发
console.log("test1 running...");
},
onTest2() {
console.log("test2 running");
}
}
};
</script>
// child1.vue
<template>
<div class="child-1">
<p>in child1:</p>
<p>props: {{pChild1}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
<!-- C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 -->
<!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) -->
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
import Child2 from "./Child2.vue";
export default {
// 【1】接受了一个数据
props: ["pChild1"],
data() {
return {};
},
inheritAttrs: false,
// 【2】设置为false
components: { Child2 },
mounted() {
// 【3】 通过$emit 与父组件通信
this.$emit("test1");
}
};
</script>
// child2.vue
<template>
<div class="child-2">
<p>in child2:</p>
<p>props: {{pChild2}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
</div>
</template>
<script>
export default {
props: ["pChild2"],
data() {
return {};
},
inheritAttrs: false,
mounted() {
// 【1】 可以直接触发
this.$emit("test2");
}
};
</script>
实例方法 | 数据
vm.$watch
// 第一种写法
watch: {
text(new, old) {
console.log(`${new}:${old}`);
}
}
// 第二种写法
const unWatch = this.$watch('text',(new,old)=>
console.log(`${new}:${old}`);
})
// 返回一个取消观察函数,用来停止触发回调
// 2秒后销毁 unWatch
setTimeout(()=> {
unWatch(); // 取消观察
},2000)
// 两种写法的结果一样,只是第二种需要在组件销毁手动销毁$watch
选项
// 为了发现【对象内部值的变化】,可以在选项参数中指定 deep: true
vm.$watch('someObject', callback, {
deep: true
})
// 在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调:
vm.$watch('a', callback, {
immediate: true
})
// 立即以 `a` 的当前值触发回调
vm.$set
是Vue.set()的别名
vm.$delete
这是全局 Vue.delete 的别名。
实例方法 | 事件
vm.$on(event, callback)
// 接收触发的函数
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
// => "hi"
vm.$once( event, callback )
监听一个自定义事件,但是只触发一次,在第一次触发之后移除监听器。
vm.$off
移除自定义事件监听器。
vm.$emit(event, [...args])
触发当前实例上的事件。附加参数都会传给监听器回调。
实例方法 | 生命周期
vm.$mount()
挂在到dom
var MyComponent = Vue.extend({
template: '<div>Hello!</div>'
})
// 创建并挂载到 #app (会替换 #app)
new MyComponent().$mount('#app')
// 同上
new MyComponent({ el: '#app' })
// 或者,在文档之外渲染并且随后挂载
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)
vm.$forceUpdate
迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
vm.$nextTick(callback)
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
//
new Vue({
// ...
methods: {
// ...
example: function () {
// 修改数据
this.message = 'changed'
// DOM 还没有更新
this.$nextTick(function () {
// DOM 现在更新了
// `this` 绑定到当前实例
this.doSomethingElse()
})
}
}
})
// 如果你要修改某个dom元素的值或者状态,当你修改完后,还想要继续使用改dom去完成接下来的操作。
// 那么这里最好只用nextTick等待dom更新完毕之后再操作(这个延时差不多是20ms)
//可以用下面代替
setTimeOut(() => {
//
}, 20)
vm.$destroy()
完全销毁一个实例。
propsData
Vue.extend的propsData 用得很少,仅用于开发环境
// vue.extend()主要用于生产组件
<body>
<h1>Vue.extend的propsData 用得很少,仅用于开发环境</h1>
<div id="head2"></div>
<script>
var CommonHeader = Vue.extend({
template:"<header>我是网站头部 {{ message }} -by {{ username }}</header>",
data:function () {
return{
message:"I am message!"
}
},
props:['username']
});
var header = new CommonHeader({
propsData:{
username:"wss"
}
}).$mount("#head2");
</script>
</body>
keep-alive
<keep-alive>
是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。他是一个抽象组件,不会渲染到DOm中
- include: 字符串或正则表达式。只有匹配的组件会被缓存。
- exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
1.用在动态组件中
<keep-alive include="test-keep-alive">
<!-- 将缓存name为test-keep-alive的组件 -->
<component></component>
</keep-alive>
<keep-alive include="a,b">
<!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
<component :is="view"></component>
</keep-alive>
<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 动态判断 -->
<keep-alive :include="includedVar">
<router-view></router-view>
</keep-alive>
<keep-alive exclude="test-keep-alive">
<!-- 将不缓存name为test-keep-alive的组件 -->
<component></component>
</keep-alive>
结合router-view
<keep-alive>
<router-view></router-view>
</keep-alive>
// 再路由跳转中如果组件没有变化,则进行缓冲
keep-alive生命周期钩子函数:activated
、deactivated
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。
router还增加了meta属性,具体请看下面两篇文章了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。