4

实例属性

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生命周期钩子函数:activateddeactivated

使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。

router还增加了meta属性,具体请看下面两篇文章了

vue-router 之 keep-alive

vue实现前进刷新,后退不刷新


Meils
1.6k 声望157 粉丝

前端开发实践者