Vue在工作中需要注意的地方

1,272 阅读9分钟

持续更新中 ······

Computed && Methods && Watch

官方传送门

1.computed

监听响应式的数据,非响应数据不可用

2.methods

方法:无论是否响应,都作为函数处理

3.watch

监听:可以在监听中调用别的函数,处理异步操作(包括节流防抖!!)

Vue filter

官方传送门

引用官方案例~~~~

定义:

当全局过滤器和局部过滤器重名时,会采用局部过滤器

在当前的script中定义一个局部的filter

filters: { //filters有s
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

全局定义!!!!!但必须在实例化Vue之前定义!!!!
Vue.filter('capitalize', function (value) { // filter没有s
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})
{{ message | filterA | filterB }} // 1
{{ message | filterA('arg1', arg2) }} // 2
  • 1.可接受多个参数filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。
  • 2.过滤器是js函数,filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。

用法

index.vue中html结构处使用

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>  

弊端(无法在script中使用)(作为工具类中的函数定义)

{{ message }}

import filterName from 'xxxxx'
<script>
computed:{
    message(){
        return filterName(args)
    }
}
</script>

TS中使用vue过滤器

使用vue-property-decorator时可以使用以下方式进行过滤器的引用

<!-- 在双花括号中 -->
{{ message | filterName }}

@Component({
    filters:{
      filterName
  }
})

Transition动画

1.Vue 提供了 transition 的封装组件,可以给任何元素和组件添加进入/离开过渡**

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点
<transition name="fade">
    <p v-if="show">hello</p>
</transition>
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

动画运行的过程:

  • 当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:

  • 检测目标组件是否应用了 CSS 过渡(transtion)或动画(animation),如果是,则添加/删除 CSS 类名。

  • 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。

  • 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)

2.使用css3动画

<transition name="bounce">
    <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
</transition>

.bounce-enter-active {
  transform-origin:left center; //解决放大缩小可能遇到的问题
  animation: bounce-in .5s;
}
.bounce-leave-active {
  transform-origin:left center; //解决放大缩小可能遇到的问题
  animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

3.自定义过渡的类名

<transition name="bounce" enter-active-class='active' leave-active-class='leave'>
    <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
 </transition>

.active {
  transform-origin:left center; //解决放大缩小可能遇到的问题
  animation: bounce-in .5s;
}
.leave {
  transform-origin:left center; //解决放大缩小可能遇到的问题
  animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

4.使用animate.css 库动画

<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1"  type="text/css">
  
  <transition
    name="custom-classes-transition" //类名随意
    enter-active-class="animated tada"   //animated必须写,否则无法进行动画
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>

4.同时使用过渡和动画

初始化渲染页面的动画

可以通过 appear 特性设置节点在初始渲染的过渡

css类名为swing
<transition
  appear //必须写,声明初始化渲染
  appear-class="swing" //可不写
  appear-to-class="swing" (2.1.8+)//版本需求
  appear-active-class="swing"
>
  <!-- ... -->
</transition>

5.动画的过渡时间

在这种情况下你可以用 <transition> 组件上的 duration 属性定制一个显性的过渡持续时间 (以毫秒计):

<transition :duration="1000">...</transition>

你也可以定制进入和移出的持续时间:

<transition :duration="{ enter: 500, leave: 800 }">...</transition>

6.Javascript钩子(可配合Velocity.js)

<transition
  :before-enter="beforeEnter"
  :enter="enter"
  :after-enter="afterEnter"
  :enter-cancelled="enterCancelled"

  :before-leave="beforeLeave"
  :leave="leave"
  :after-leave="afterLeave"
  :leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
// ...
当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。
否则,它们将被同步调用,过渡会立即完成。methods: {
  // --------
  // 进入中
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // 离开时
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}

7.多元素或组件过渡

当有相同标签名的元素切换时,Vue 为了效率只会替换相同标签内部的内容,需要通过 key 特性设置唯一的值来标记以让 Vue 区分

给在 <transition> 组件中的多个元素设置 key 是一个更好的实践。

<transition mode='in-out'>   //in-out先进入后移除   out-in 先移除后进入
    <div v-if='show' key='hello'>hello</div>
    <div v-else key='bye'>bye</div>
</transition>

组件过渡动画可以使用is的特性来完成,不需要使用key来进行区分

8.列表过渡

<transition-group>

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

相当于

<transition>
  <span>
    {{ item }}
  </span>
  <span>
    {{ item }}
  </span>
  <span>
    {{ item }}
  </span>
</transition>

解析 DOM 模板时的注意事项

有些 HTML 元素,诸如<ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。 而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。 这会导致我们使用这些有约束条件的元素时遇到一些问题。 例如:

<table>
    <blog-post-row></blog-post-row>
</table> 

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

<table>
    <tr is="blog-post-row"></tr>
</table> 

需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:

  • 字符串 (例如:template: '...')
  • 单文件组件 (.vue)
  • <script type="text/x-template">

参数校验

我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 匹配任何类型)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

循环引用

循环引用传送门

1.递归组件

组件在自己的模板中调用自身的。需要通过 name 选项来做这件事:

  • 局部注册
name: 'unique-name-of-my-component'
  • 全局注册 当你使用 Vue.component 全局注册一个组件时,这个全局的 ID 会自动设置为该组件的 name 选项。
Vue.component('unique-name-of-my-component', {
  // ...
})

注意点:递归调用需要有一个边界值来终止(比如使用v-if来处理),否则会导致无限循环

name: 'stack-overflow',
template: '<div><stack-overflow></stack-overflow></div>'

上述组件将会导致“max stack size exceeded

组件之间的循环引用

假设你需要构建一个文件目录树,像finder或资源管理器那样的。你可能有一个 <tree-folder> 组件:

<p>
  <span>{{ folder.name }}</span>
  <tree-folder-contents :children="folder.children"/>
</p>

还有一个 <tree-folder-contents> 组件:

<ul>
  <li v-for="child in children">
    <tree-folder v-if="child.children" :folder="child"/>
    <span v-else>{{ child.name }}</span>
  </li>
</ul>

你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!当通过 Vue.component 全局注册组件的时候,这种问题不存在

然而,如果你使用一个模块系统依赖/导入组件,例如通过 webpackBrowserify,你会遇到一个错误:

Failed to mount component: template or render function not defined.

解释:

我们先把两个组件称为 A 和 B。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要给模块系统一个点,在那里“A 反正是需要 B 的,但是我们不需要先解析 B。”

在我们的例子中,把 <tree-folder> 组件设为了那个点。我们知道那个产生悖论的子组件是 <tree-folder-contents> 组件,所以我们会等到生命周期钩子 beforeCreate 时去注册它:

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}

或者,在本地注册组件的时候,你可以使用 webpack 的异步 import:(个人推荐)

components: {
  TreeFolderContents: () => import('./tree-folder-contents.vue')
}

混入

用处:

分发Vue组件中的可复用功能

使用

定义mixin
var mixin = {
    created:function(){
        this.hello()
    },
    methods:{
        hello:function(){
            console.log('hello mixin')
        }
    }
}
在组件中使用mixin
import mixin from xxxxxxx
var Component = Vue.extend({
    mixins:[mixin]
})

var comp = new Component() // 输出:hello mixin

注意点:

  • 数据对象:当组件使用混入对象时,混入的对象选项都会进入该组件本身的选项中,如果有同名的属性和方法,以组件内部的对象为主,否则合并数据对象
  • 钩子函数:同名的钩子函数将合并为一个数组,并且混入对象的钩子将在组件钩子之前被调用
  • 全局混入:全局混入将影响每一个之后创建的Vue实例,不建议使用,如果需要,可以作为插件发布使用

自定义选项合并策略

自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以通过 Vue.config.optionMergeStrategies 进行处理 有需要的直接传送门

自定义指令

官方传送门(个人觉得很详细了)