【Vue2】基础知识点梳理

1,476 阅读3分钟

基础

创建实例

创建 Vue 实例并挂载到指定的 DOM 节点上:

<div id="app" />
<script>
  // 定义配置
  const options = {
    el: '#app',
    data() {
      return {};
    },
  };
  // 创建Vue实例
  const vm = new Vue(options);
  // 获取实例属性和调用实例方法
  vm.$propertyName;
  vm.$methodName();
</script>

模板语法

<div>文本插值 {{text}}</div>
<div v-text="text"></div>
<div v-html="html"></div>
<div v-once>内容不会改变 {{msg}}</div>
<input v-modle="value" />
<div :attribute="varOrExp"></div>
<div @event="varOrExp"></div>
<div :[attribute]="varOrExp"></div>
<div @:[event]="varOrExp"></div>

样式语法

元素的classstyle属性通常为复杂的字符串。所幸 Vue 支持:class:style的对象形式和数组形式:

const options = {
  data() {
    return {
      obj: {
        a: true,
        b: false,
      },
      arr: ['a', 'b'],
    };
  },
};
<div class="default" :class="obj"></div>
<div class="default" :class="arr"></div>
<!--会被渲染成-->
<div class="default a"></div>
<div class="default a b"></div>

元素的style属性同理,且 Vue 会智能地为其添加浏览器引擎前缀。

条件渲染

v-if是真正意义上的条件渲染,v-show则是惰性渲染(先渲染,通过切换display属性来切换元素的显示与否),当需要频繁切换显示状态时,应使用后者:

<div v-if="varOrExp1"></div>
<div v-else-if="varOrExp2"></div>
<div v-else></div>
<div v-show="varOrExp3"></div>

条件渲染在切换时,默认复用元素,可以添加key属性来防止复用:

<!--<label>元素会被复用,<input>元素则不会-->
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input" />
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input" />
</template>

<template>元素本身不会被渲染,其常用于充当包裹元素。

循环渲染

使用v-for指令进行循环渲染。其中的key属性是为了标识 vdom,使得在 vdom diff 时,能通过尽可能地移动已有元素来降低 DOM 操作成本;当未设key属性时,则采取就地更新的原则:

<div v-for="(val,idx) of [1,2,3]" :key="val.id"></div>
<div v-for="(val,key,idx) of {a:1,b:2,c:3}" :key="val.id"></div>
<div v-for="val in 10" :key="val" />

组件

注册组件

组件实际上是带预定配置、可复用的 Vue 实例:

// 局部组件ComponentLocal,
// 只能在全局组件ComponentGlobal内部使用
Vue.component('ComponentGlobal', {
  components: { ComponentLocal },
  template: '<div><component-local /><span>hello!</span></div>',
});

自动化注册请见此文

生命周期钩子

const options = {
  // 在实例创建后=
  beforeCreate() {},
  // 在options初始化后
  created() {},
  // 在模板编译为vdom后
  beforeMount() {},
  // 在vdom挂载到dom后
  mounted() {},
  // 在数据更新后
  beforeUpdate() {},
  // 在虚拟dom和dom更新后
  updated() {},
  // 在实例销毁前
  beforeDestroy() {},
  // 在实例销毁后
  destroyed() {},
};

props

HTML 中的 attribute 名称大小写不敏感,如title等同于Title;所以在 Vue 中的 proppostTitle在 HTML 中应写成post-title

const options = {
  name: 'blog-post',
  props: {
    postTitle: {
      type: String,
      default: 'DEFAULT POST TITLE',
    },
  },
};
<blog-post post-title="Hello Post!" />

可以一次性传入所有的props

const options = {
  name: 'blog-post',
  data() {
    return {
      post: {
        id: 1,
        title: 'My Journey with Vue',
      },
    };
  },
};
<blog-post v-bind="post"></blog-post>
<!--等价于-->
<blog-post :id="post.id" :title="post.title"></blog-post>

props由父组件单向传播给子组件。$attrs为父组件传给子组件、但未注册为props的属性,该属性会作为 HTML attribute,被添加到子组件根标签中;若将子组件的inheritAttrs设为false,则该属性不会被添加到子组件根标签中,但$attrs的值不受影响。

methods

<div @click="method1"></div>
<div @click="method2('param')"></div>
<div @click="method3('param',$event)"></div>
const options = {
  methods: {
    method1(event) {},
    method2(param) {},
    method3(param, event) {},
  },
};

事件具有修饰符,如不带修饰符默认在冒泡阶段监听事件,带修饰符.capture在捕获阶段监听事件,以及其他的修饰符.prevent.stop.self.once。除此以外,还有按键修饰符@keyup.page-down,鼠标修饰符@click.left,系统修饰符@click.ctrl@keyup.alt,精确修饰符.exact

watch 和 computed

const options = {
  // 侦听器
  watch: {
    a: {
      deep: true,
      immediate: true,
      handler(newVal, oldVal) {},
    },
  },
  // 计算属性:基于侦听器
  computed: {
    // 侦听firstName和lastName,会将结果缓存
    fullName: {
      get() {
        return this.firstName + this.lastName;
      },
      set(val) {
        // ...
      },
    },
  },
};

filters

<div>{msg | transform('param')}</div>
// 全局
Vue.filter('upper', function (value, param) {
  return '...';
});

// 局部
const options = {
  filters: {
    upper(value, param) {
      return '';
    },
  },
};

directives

<div v-focus></div>
// 全局
Vue.directive('focus', {
  // 参数有el、binding、vnode、oldVnode
  bind() {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {},
});

// 局部
const options = {
  directives: {
    focus: {
      // ...
    },
  },
};

mixins

混入规则为,同名钩子函数合并为数组,依次调用,其余属性直接被替代:

const mixinOptions = {
  // ...
};

// 全局混入
Vue.mixin(mixinOptions);

// 局部混入
Vue.component('component-be-mixin', {
  minxins: [mixinOptions],
  // ...
});

双向绑定

<input v-model="varOrExp" />
<!--等价于-->
<input :value="varOrExp" @input="varOrExp = $event.target.value" />

v-model指令对于不同的元素,有着不同的绑定属性和事件:

  • 对于<text> 元素和 <textarea>元素,对应 value 属性和 input 事件。
  • 对于<checkbox> 元素和 <radio>元素,对应 checked 属性和 change 事件。
  • 对于<select,对应> 元素,对应 value 属性和 change 事件。

亦可自定义对应的属性和事件:

const options = {
  model: {
    prop: 'checked',
    event: 'change',
  },
};

v-model有修饰符,如.lazy.number.trim

同步 props

.sync修饰符,用于在子组件中便捷地修改prop的值:

<!--template-parent-->
<child :inner-title="title" @update:inner-title="title = $event"></child>
// component-child
this.$emit('update:inner-title', newTitle);

父组件模板可简写为:

<child :inner-title.sync="title"></child>

访问子组件

<component-name ref="a" />
const childComponent = this.$refs['a'];

插槽

默认插槽:

<!--template-->
<div>
  <strong>Error!</strong>
  <slot></slot>
</div>
<!--use-->
<alert-box> Something bad happened. </alert-box>

具名插槽:

<!--template-->
<div>
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <!--name="default"-->
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
<!--use-->
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

作用域插槽(让父组件访问到子组件插槽内部的数据):

<!--template-->
<span>
  <slot :user="user"> {{ user.lastName }} </slot>
</span>
<!--use,slotProps是default插槽作用域-->
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

动态组件和异步组件

动态组件:

<!--默认不缓存状态-->
<component-name :is="currentComponent" />

<!--使用keep-alive组件缓存状态-->
<keep-alive>
  <component-name :is="currentComponent" />
</keep-alive>

异步组件:

// 第2个参数返回的类型为Promise
Vue.component('async-component', function (resolve, reject) {
  setTimeout(function () {
    const options = {
      template: '<div>I am async!</div>',
    };
    resolve(options);
  }, 1000);
});

处理异步组件的加载状态:

Vue.component('async-component', () => ({
  // 需要加载的组件 (类型应该为Promise)
  component: import('./MyComponent.vue'),
  // 正在加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示LoadingComponent的延时时间
  delay: 200,
  // 加载的限定时间
  timeout: 3000,
}));

过渡和动画

进入/离开过渡

单元素/组件过渡(对v-showv-if:is起作用):

【1】CSS 过渡:

<transition name="slide-fade" mode="in-out" :duration="1000">
  <component-name v-if="varOrExp" />
</transition>
.slide-fade-enter-active {
  transition: all 0.3s ease;
}
.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter,
.slide-fade-leave-to {
  transform: translateX(10px);
  opacity: 0;
}

【2】动画过渡:

HTML 模板同上。

.slide-fade-enter-active {
  animation: /*...*/ ;
}
.slide-fade-leave-active {
  animation: /*...*/ ;
}

【3】钩子过渡:

<transition
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"
  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
const options = {
  mtehods: {
    beforeEneter(el) {
      el.style.opacity = 0;
    },
    enter(el, done) {
      done();
    },
  },
};

多元素/组件过渡(对v-for中的v-showv-if:is起作用):

<transition-group name="list" tag="p">
  <span v-for="item in items" :key="item.id"> {{item}} </span>
</transition-group>

过渡方式与单元素/组件过渡的相同,额外的是,可指定元素移动时的过渡:

.list-move {
  transition: transform 1s;
}

状态过渡

指基于响应式数据,平滑过渡颜色、数值等的变化。

原理

响应式绑定

cn.vuejs.org/v2/guide/re…

虚拟 dom

每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。

就像家谱树一样,每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。

生态系统

插件

使用插件(Vue 会自动阻止多次注册相同插件):

import MyPlugin from 'my-plugin';
Vue.use(MyPlugin, options);

编写插件:

MyPlugin.install = function (Vue, options) {
  // 通过一系列全局注册或混入...
  Vue.directive();
  Vue.mixin();
  Vue.$method = function () {};
  Vue.prototype.$method = function () {};
};

Vue 的核心插件有:

  • VueRouter:路由管理。
  • Vuex:状态管理。
  • Vue SSR:服务端渲染。

工具

Vue 的官方工具有:

  • Devtools。
  • Vue Cli。
  • Vue Loader。