基础API与扩展

Misaka10032单文件渲染refprops大约 5 分钟

ref

1.作用:用于给节点打标识

2.应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象

3.读取方式:this.$refs.xxxxxx

4.读取时机,组件或 DOM 元素成功渲染挂载后,一般是在 mounted 或挂载成功后的触发事件中

<template>
  <div>Hello</div>
</template>

<script>
export default {
  methods: {
    sayHello() {
      console.log("Hello");
    },
  },
};
</script>
<template>
  <div>
    <div ref="div">Hello</div>
    <Hello ref="hello" />
  </div>
</template>

<script>
import Hello from "./Hello";

export default {
  components: { Hello },
  mounted() {
    console.log(this.$refs.div.innerText);
    // 可以调用组件内部的methods或data属性等
    this.$refs.hello.sayHello();
  },
};
</script>

props

1.作用:用于父组件给子组件传递数据

2.读取方式一: 只指定名称props: ['name', 'age', 'setName']

3.读取方式二: 指定名称和类型

props: {
	name: String,
	age: Number,
	setName: Function
}

4.读取方式三: 指定名称/类型/必要性/默认值

props: {
	name: {type: String, required: true, default:xxx},
}

注意:接收到的 props 是不能被自身修改的。

混入

提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

局部混入:mixins: [ 'xxx' ]

全局混入:Vue.mixin(xxx)

// mixin.js
export const mixin = {
  methods: {
    showName() {
      alert(this.name);
    },
  },
};
<!-- Main.vue -->
<template>
  <!-- 因为mixins已经混入了methods,此处可直接使用showName方法 -->
  <div @click="showName">{{ name }}</div>
</template>

<script>
import { mixin } from "./mixin.js";

export default {
  name: "Main",
  data: () => ({
    name: "mainName",
  }),
  mixins: [mixin],
};
</script>

插件

1.Vue 插件是一个包含 install 方法的对象

2.通过 install 方法给 Vue 或 Vue 实例添加方法, 定义全局指令等

本质:包含 install 方法的一个对象,install 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据。

定义插件:

export default {
  install(Vue) {
    // 全局过滤器
    Vue.filter('mySlice', function(value) {
      return value.slice(0, 4)
    })
  }

  // 定义全局指令
  Vue.directive('fbind', {
    // ...
  })

  // 定义混入
  Vue.mixin({
    // ...
  })

  // 给Vue原型上添加一个方法,vm和vc均可使用
  Vue.prototype.hello = () => { alert('Hello') }
}

使用插件,Vue.use()

插槽

作用

让父组件可以向子组件指定位置插入 html 结构,也是一种组件间通信方式,适用于 父组件 ===> 子组件

分类

默认插槽、具名插槽、作用域插槽。

使用方式

1.默认插槽

<!-- 父组件 -->
<template>
  <Category>
    <div>html1结构1</div>
  </Category>
</template>

<!-- 子组件 -->
<template>
  <div>
    <!-- 定义插槽 -->
    <slot>插槽默认内容...如果父组件中写入了默认插槽,此处内容会被覆写</slot>
  </div>
</template>

2.具名插槽

<!-- 父组件 -->
<template>
  <Category>
    <template slot="center">
      <div>html结构1</div>
    </template>
    <template v-slot:footer>
      <div>html结构2</div>
    </template>
  </Category>
</template>

<!-- 子组件 -->
<template>
  <div>
    <!-- 定义插槽 -->
    <slot name="center">插槽默认内容...</slot>
    <slot name="footer">插槽默认内容...</slot>
  </div>
</template>

3.作用域插槽

理解:数据在组件的自身,但根据数据生成的结构需要组件使用者来决定。(真正 data 数据在子组件中,但使用数据所遍历出来的结构由父组件决定)

<!-- 父组件 -->
<template>
  <Category>
    <template scope="scope">
      <ul>
        <li v-for="item in scope.games" :key="item">{{ item }}</li>
      </ul>
    </template>
  </Category>

  <Category>
    <template slot-scope="{ games }">
      <ul>
        <li v-for="item in games" :key="item">{{ item }}</li>
      </ul>
    </template>
  </Category>
</template>

<!-- 子组件 -->
<template>
  <div>
    <!-- 定义插槽 -->
    <slot :games="games"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      games: ["1", "2", "3", "4"],
    };
  },
};
</script>

nextTick

nextTick 就是设置一个回调,用于异步执行。

就是把你设置的回调放在 setTimeout 中执行,这样就算异步了,等待当时同步代码执行完毕再执行。

this.$nextTick((_) => {
  this.$refs.saveTagInput.$refs.input.focus();
});

当页面上的元素被重新渲染之后,才会执行指定回调函数中的代码。

实现原理

  • 存在 回调数组 里。每次调用 nextTick,便往数组里面 push 设置的回调
  • 只注册一个 setTimeout,时间为 0,用于遍历 回调数组,然后逐个执行子项
  • 同步代码执行完毕,setTimeout 自然会执行
  • Vue 不止使用 setTimeout 实现 nextTick;会判断 promise 是否存在,选择任务类型。如果 promise 存在,就使用微任务。

注意:Vue 在一个 tick 中多次更新数据页面只会更新一次

即使在 Vue 中多么频繁地修改数据,最后 Vue 页面只会更新一次。

例如: 数据 name 被 页面引用,name 会收集到 页面的 watcher; name 被修改时,会通知所有收集到的 watcher 进行更新(watcher.update); 如果 name 一时间被修改三次时,按道理应该会通知三次 watcher 更新,那么页面会更新三次,但是最后只会更新一次。 这是因为: 当数据变化后,把 watcher.update 函数存放进 nextTick 的 回调数组中,并且会做过滤。 通过 watcher.idopen in new window 来判断 回调数组 中是否已经存在这个 watcher 的更新函数不存在,才 push。 之后 nextTick 时 遍历回调数组,便会执行了更新。

所以当三次修改数据的时候,会 push 回调数组 三个 watcher.update,但是只有第一次是 push 成功的,其他的会被过滤掉,因为已经存在了。 所以,不管你修改多少次数据,nextTick 的回调数组中只存在唯一一个 watcher.update,从而页面只会更新一次。

过渡与动画

过渡

作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。

Vue过渡动画
Vue过渡动画

元素进入样式:

  • 起点:v-enter
  • 过程:v-enter-active
  • 终点:v-enter-to

元素离开样式:

  • 起点:v-leave
  • 过程:v-leave-active
  • 终点:v-leave-to

包裹

使用<transition>包裹要过渡的元素,并配置name属性

appear属性:给元素添加初始过渡效果

<template>
<transition name='hello' appear>
	<h1 v-show="isTrue">test</h2>
</transition>
</template>

<script>
export default {
  data: () => ({
    isTrue: true
  })
}
</script>

若有多个元素需要过渡,则需要<transition-group>,且每个元素都要指定key值