Vue

1.通过脚手架安装

npm install -g @vue/cli // 全局安装vue/cli脚手架
vue --version // 查看vue版本
vue create hello-world // 创建项目
vue ui // 以图形化界面管理项目

2.目录结构

/public目录下存放的index.html为基础html,vue生成的html页面文件均是以此文件为模板基础产生的。
/src目录下为项目源文件,分为assets资源文件夹、components组件文件夹、views页面文件夹、store状态管理文件夹、modules多入口文件夹,单入口时不需要。
/dist目录为发布目录。

3.简介

单页面单入口时,main.js为入口文件,会将vue实例挂载到#app节点上。.vue文件包含<template></template><script></script><style lang="less"></style>。注意style样式要注明样式文件语言,template内首层节点为单节点。

4.vue.config.js文件配置简介

module.exports = {
  publicPath: '/wxapp/', // 一般为public根路径
  outputDir: 'dist/wxapp', // build的项目存放路径
  assetsDir: '', // 放置生成的静态资源(js、css、img、fonts)的(相对于 outputDir 的)目录
  indexPath: 'index.html', // 指定生成的 index.html 的输出路径 (相对于 outputDir),也可以是一个绝对路径
  pages: { // 多页面入口配置
    page1: {
      entry: 'src/modules/page1/page1.js', // 应用入口配置,相当于单页面应用的main.js,必需项
      template: 'public/index.html', // 应用的模版,相当于单页面应用的public/index.html,可选项,省略时默认与模块名一致
      filename: 'page1.html', // 编译后在dist目录的输出文件名,可选项,省略时默认与模块名一致
      title: 'page1标题', // 标题,可选项,一般情况不使用,通常是在路由切换时设置title;需要注意的是使用title属性template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
    },
    page2: {}
  },
  // 其余项目配置详见
}

5.多入口页面

多页面入口时,不仅需要配置vue.config.js文件中的pages字段,还要将多页面文件的入口文件脚本、入口vue文件分别处理,若有router路由配置的话,还应分别配置路由router文件。入口JS文件:

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import store from '@/store/store.js'
import MainLoan from './MainLoan.vue'
import '@/assets/css/cssreset-mobile.css'
import 'we-vue/lib/style.css'
import WeVue from 'we-vue'
import '@/assets/css/main-mobile.css'
import router from './router'
import Fastclick from 'fastclick'
Vue.config.productionTip = false
Vue.use(WeVue)
Vue.use(VueAxios, axios)
Fastclick.attach(document.body)
new Vue({
  router, // 挂载路由
  store, // 挂载全局状态
  render: h => h(MainLoan) // 初始模板选择
}).$mount('#app')

6.vue实例

<script></script>脚本标签内,基本类型如下:

import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'app', // 页面或者组件名称
  components: { // 本组件需要使用的下级组件声明
    HelloWorld
  },
  props: {
        prop1: String/Object/Number // 上级组件传递的参数
  },
  data() { // data数据,需要使用函数返回
    return {
    index: 1,
      temp: 'nali',
      title: 'ttx',
      watchIndex: 1,
    }
  },
  computed: { // 计算属性,监听值无变化时,会有计算缓存,不会重复求值
        getIndex() {
          return this.index + 1
        }
  },
  methods: { // 内部方法定义
        test() {
          console.log('test')
        }
  },
    watch: { // 监听实例数据变动,可用于异步或开销较大的处理,一般无返回值
        index(value) {
            this.watchIndex = this.index
        }
    },
  filters: { // 过滤器,对传入的值进行包装处理
        capitalize(value) {
            return value.toString()    
        },
    },
  // 以下为生命周期回调
  beforeCreate() {}, // 实例创建之前调用
  created() {}, // 实例创建成功,此时 data 中的数据显示出来了
  beforeMount() {}, // 数据中的 data 在模版中先占一个位置
  mounted() {}, // 模版中的 data 数据直接显示出来了
  beforeUpdate() {}, // 当 data 数据发生变化调用,发生在虚拟 DOM 重新渲染和打补丁之前
  updated() {}, // 数据更改导致的虚拟 DOM 重新渲染和打补丁
  beforeDestroy() {}, // 在 vue 实例销毁之前调用,此时实例任然可用
  destroyed() {}, // 在vue实例销毁之后调用,实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
}

7.数据展示绑定

模板展示内容内,通过进行绑定,如<div></div>;若要进行一次性插值,节点上加入v-once指令即可,次节点内数据绑定一次后将不会随data数据变化而更新。这个称为 Mustache 语法。Mustache语法不能用于HTML节点上,节点上应该使用vue指令。
Mustache语法内可以使用JS表达式,且只能为单个表达式。

{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}

8.vue指令

指令是带有v-前缀的特殊特性。指令后数据绑定直接使用data属性即可,不用Mustache语法。

v-bind:指令可以用于响应式地更新HTML特性:<a v-bind:href="url">...</a>v-bind:可简写为:
v-on:用于监听 DOM 事件:<a v-on:click="doSomething">...</a>v-on:可简写为@
v-if:用于条件性地渲染一块内容,<h1 v-if="awesome">Vue is awesome!</h1><h1 v-else>Oh no</h1>
v-show:用于节点的显示与隐藏;
v-for:用于循环渲染;
v-model:用于数据双向绑定;

9.指令修饰符

.修饰符半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。修饰符可以级联使用。

<form v-on:submit.prevent="onSubmit">...</form>

常用修饰符:
事件修饰:

`.stop`: event.stopPropagation(),防止事件冒泡;
`.prevent`: event.preventDefault(),防止执行预设的行为;
`.capture`: 与事件冒泡的方向相反,事件捕获由外到内;
`.self`: 只会触发自己范围内的事件,不包含子元素;
`.once`: 只会触发一次;
`.passive`: 不会等待事件回调执行完毕才继续执行下一次事件,等于事件回调时异步的。有助于提升连续触发事件的性能。

键盘修饰符:

`.enter`:回车键;
`.tab`:制表键;
`.delete`:含delete和backspace键;
`.esc`:返回键;
`.space`: 空格键;
`.up`:向上键;
`.down`:向下键;
`.left`:向左键;
`.right`:向右键;
类似于`@keyup.esc`。

鼠标修饰符:

`.left`:鼠标左键;
`.middle`:鼠标中间滚轮;
`.right`:鼠标右键;

自定义按键修饰符别名:

<div id="app">
    <input type="text" v-on:keydown.f5="prompt()">
</div>

Vue.config.keyCodes.f5 = 116

10.class与style绑定

通过v-bind:class=指令动态地切换节点class属性。这个元素上已经存在的类不会被覆盖。

对象语法:

<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
// vue实例中
data() {
    return {
        isActive: true,
        hasError: 1
    }
}

也可以直接使用class的对象:

<div v-bind:class="classObject"></div>

data: {
  classObject: { // 此对象放于计算属性最好,可以动态结算更新
    active: true,
    'text-danger': false
  }
}

数组语法,类似于直接将class名列出给节点:

<div v-bind:class="[activeClass, errorClass]"></div>
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
// <div class="active text-danger"></div>

内联样式绑定:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
  activeColor: 'red',
  fontSize: 30
}
// 或者
<div v-bind:style="styleObject"></div>
data: { // 同样,计算属性更加灵活方便
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}
// 数组语法可以将多个样式对象应用到同一个元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>

11.条件渲染

v-if预计传值得真假判断去确定是否需要渲染html结构;

<h1 v-if="awesome">Vue is awesome!</h1>

当需要批量显示与隐藏多节点时,可以使用<template>v-if指令进行包裹,最终渲染不会包含<template>节点。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-if对应的v-elsev-else-if指令:

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

另外,vue在切换渲染时,会服用已有的元素,若要表明两元素不可服用,需要在元素节点上定义不同key值:

<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>

v-show用于节点的显示与隐藏,仅仅变换了display值;v-show不支持<template>元素。

12.循环渲染

v-for:循环渲染。v-for节点渲染时,节点会被不断复用,当数据顺序变更或减少时,节点不会全部重新渲染,但会就近更新节点简单数据,因此只适用于不依赖子组件状态的情况。
当节点需要跟踪每个节点身份时,请使用v-bind:key为节点添加唯一标示。

<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})
// index为渲染索引
<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

也可以用of替代in作为分隔符,当使用in时,可以遍历对象属性。

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})
// name为属性名
<div v-for="(value, name) in object">
  {{ name }}: {{ value }}
</div>
// index为索引
<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>

为循环节点添加唯一标示,不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值:

<div v-for="item in items" v-bind:key="item.id"><!-- 内容 --></div>

v-for也可以接受整数。在这种情况下,它会把模板重复对应次数。

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

v-for指令与v-if指令同时使用时,v-for指令优先级高于v-if指令。

13.数组数据的更新检测

vue数据长度隐式更新或数组被替换时,vue会触发数据更新与视图更新;如push();pop();shift();unshift();splice();sort();reverse()或数组替换方法均会触发数据更新。
但当用索引更新某一个数组项或者显示地定义数组长度时,数据更新不会检测到。如arr[1] = 2; arr.length = 5;
当需要使用上述方式时,可以使用以下方式变更触发视图更新:

Vue.set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)
vm.$set(vm.items, indexOfItem, newValue)
vm.items.splice(newLength)

同理,对象数据变更时,vue也不能检测对象属性的添加与删除。对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性,但可以通过Vue.set向对象中添加响应属性。

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})
Vue.set(vm.userProfile, 'age', 27)
vm.$set(vm.userProfile, 'age', 27) // 或直接调用通用方法

若有多个属性要一次性添加,不应该将多个属性直接添加到原对象上,而是应该创建一个新对象去替换原对象:

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

14.事件处理

v-on指令监听DOM事件;若需要在内联语句处理器中访问原始的DOM事件。可以用特殊变量$event把它传入方法;

<button @click="test($event)"></button>
// ...
methods: {
    test(e) {
        e.stopPropagation()
    }
}

15.表单输入绑定

v-model指令在表单<input><textarea><select>元素上创建双向数据绑定。v-model会忽略表单元素的valuecheckedselected的初始值。inputtextarea输入时,中文、日文和韩文等输入法,没有输入完毕不会更新数据。

修饰符:
.lazyv-model在每次input事件触发后将输入框的值与数据进行同步(除了上述输入法组合文字时)。你可以添加.lazy修饰符,从而转变为使用change 事件进行同步;

<input v-model.lazy="msg" >

.trim: 自动过滤用户输入的首尾空白字符;

16.组件基础

对于重复性的结构,组件的使用将大大简化节点结构的书写。组件和页面类似,均有自己独立的实例与作用域。组件使用时,需要先注册才能被使用。注册分全局注册和局部注册。组件使用时,需要使用短横线分隔命名。

<HelloWorld msg="Welcome to Your Vue.js App"/> // 使用
import HelloWorld from '@/components/HelloWorld.vue' // 引入
export default {
  name: 'home',
  inheritAttrs: false, // 组件不继承使用父组件传入的prop为定义的属性
  components: { // 注册
    HelloWorld
  }
}

向子组件传递数据props

// HelloWorld组件中
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}

每一个组件必须只有一个根节点,多个时会报错。父组件的数据变化可以引起子组件的数据变化,但子组件内数据变化不会传递到父组件,但子组件需要通知父组件时,可以使用$emit()向父组件派发事件,当父组件由对该事件进行监听时,就会触发父组件事件,达到子组件通知父组件的效果。

// 父组件
<blog-post  v-on:enlarge-text="enlargeText"></blog-post>
data() {
    postFontSize: 16
},
methods: {
    enlargeText(addition) { // 也可以用$event进行访问
        this.postFontSize += addition
    }
}

// 子组件
<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

当在组件上使用v-model进行值绑定时,等价于:

<input v-model="searchText">
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value"> // value和input必须绑定才有效果

<custom-input v-bind:value="searchText" v-on:input="searchText = $event"></custom-input>
Vue.component('custom-input', {
    props: ['value'], // 组件的props必须包含value
  template: '<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)"> // 事件需通过input传出
})

组件的prop可以是数组,可以是对象集。当使用对象集时,可以指定各个属性的接受值类型。任何类型的值都可以传递给prop

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number, Date, Symbol],
    // 必填的字符串
    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
      }
    }
  }
})

若需要向prop传入一个对象的所有属性,可使用不带参数的v-bind

post: { id: 1, title: 'My Journey with Vue' }
<blog-post v-bind="post"></blog-post>
// 等价于
<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>

注意组件的数据传递请遵守单项数据原则,由父组件去改变传递的数据值,子组件不应该改变传递的值,若有需要,请使用子组件事件派发通知父组件改变。

组件的prop接收到未定义的属性时,未定义的属性会直接添加到组件的根节点上。另外,父节点传入的属性一般会覆盖子组件的同名属性,但classstyle会并存叠加。

17.自定义事件

自定义事件的事件名不会用作一个JS变量名或者属性名,所有没有必要使用驼峰结构,且v-on事件监听时,会自动转换为小写,故推荐使用-分隔的命名方式。

18.插槽

自定义的组件中,可以使用模板代码或html结构对组件进行合成,可以理解为prop接收的是JS数据,而插槽接收的是html结构。如果组件内没有包含<slot>元素,则组件标签内所有内容均会被舍弃。

<navigation-link url="/profile">Your Profile</navigation-link>
// 模板
<a v-bind:href="url" class="nav-link"><slot></slot></a>
// 渲染为
<a v-bind:href="/profile" class="nav-link">Your Profile</a>

卡槽的作用域与组件的作用域一致,父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

预置内容:当一个组件中有<slot>结构但是父组件使用该组件时,没有传递slot值,则会展示出默认的预置内容。

<button type="submit"><slot>Submit</slot></button>
// 使用
<submit-button></submit-button>
// 渲染
<button type="submit">Submit</button>
// 使用
<submit-button>save</submit-button>
// 渲染
<button type="submit">save</button>

具名插槽:<slot>插槽带有name属性值,可以让父组件在使用时,传递特定的内容到指定的位置。<slot>属性在不设置name属性时,默认name属性值为default。父组件中任何没有被包裹在带有v-slot<template>中的内容均会被视为默认<slot>的内容。注意v-slot指令只能用于<template>节点上,除非组件只有默认插槽,不过这时候有无v-slot已经不重要了。

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
// 使用
<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>
// 渲染
<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

作用域插槽:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译;若需要向卡槽中传递数据,则可以使用插槽prop。在<slot>上绑定具名属性值,在父组件中给v-slot带一个值来定义我们提供的插槽prop的名字。

<span><slot v-bind:user="user">{{ user.lastName }}</slot></span>
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

19.动态组件

当组件通过is属性进行动态切换时,不能组件之间会进行不断的销毁与创建。若需要将组件销毁前的状态保存下来,可以使用<keep-alive>元素进行包裹。当使用<keep-alive>时,内部组件必须要有唯一名字,否则无效。

<component v-bind:is="currentTabComponent"></component>
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

20.边界情况

访问根实例:在每个new Vue实例的子组件中,其根实例可以通过$root属性进行访问。

new Vue({
  data: { foo: 1 },
  computed: {
    bar: function () { /* ... */ }
  },
  methods: {
    baz: function () { /* ... */ }
  }
})
// 子组件中,可以把根vue实例作为一个简单的全局store来使用:如下
this.$root.foo
this.$root.foo = 2
this.$root.bar
this.$root.baz()

访问父组件实例$parent属性可以用来从一个子组件访问父组件的实例。与$root类似,但不建议使用。

访问子组件实例或者子元素:可以在子组件或者节点上添加ref属性赋予一个标记ID,然后通过$refs访问这个组件或者元素。注意$refs属性只在定义ref的组件实例内有效。同样地,ref也应尽量减少使用。

// base-input组件
<input ref="input">
// 使用base-input组件
<base-input ref="usernameInput"></base-input>
methods: {
  // 用来从父级组件聚焦输入框
  focus: function () {
    this.$refs.input.focus()
  }
}

21.进入离开过渡动画

单元素/组件的过渡:使用<transition name="actionName"></transition>包裹。若过渡没有检测到CSS动画定义,也没有检测到钩子函数,则节点的显示与隐藏将会在下一帧(显示动画帧update)执行

<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>

new Vue({
  el: '#demo',
  data: {
    show: true
  }
})

.fade-enter-active, .fade-leave-active { // 动画执行时样式
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to { // 渐入状态和渐出状态
  opacity: 0;
}

过渡类名:
v-enter: 元素被插入之前状态,插入之后下一帧移除;
v-enter-active: 元素被插入的前一帧生效,进入动画执行时间内有效,动画完成后移除;
v-enter-to: 元素被插入后的下一帧生效,动画完成后移除;有点类似于enter-active,但生效时间晚3帧;
v-leave: 元素离开动画触发那一帧生效,下一帧移除;
v-leave-active: 元素离开动画触发那一帧生效,离开动画执行时间内有效,动画完成后移除;
v-leave-to: 元素离开动画触发下一帧生效,离开动画执行时间内有效,动画完成后移除;

自定义过渡类名
enter-classenter-active-classenter-to-classleave-classleave-active-classleave-to-class自定义动画类名,他们的优先级高于普通类名。用于vue过渡动画和第三方库结合较好。

<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
    <p v-if="show">hello</p>
</transition>

多元素多节点动画
<transition-group></transition-group>

22.混入

类似于对象继承的一个东西,组件在实例化之前将预先设定或者公共的属性添加到实例化对象上。当有许多组件有公共的部分的时候使用起来就比较方便。
data对象会如下方式合并:

// 混入对象
var mixin = {
  data: function () {
    return {
      message: 'hello',
      foo: 'abc'
    }
  }
}
// 组件使用
new Vue({
  mixins: [mixin],
  data: function () {
    return {
      message: 'goodbye',
      bar: 'def'
    }
  },
  created: function () {
    console.log(this.$data)
    // => { message: "goodbye", foo: "abc", bar: "def" }
  }
})

混入对象会依次优先被复制到组件上,组件定义的内容会最后复制到组件上,产生自定义修改效果。另外:同名的钩子函数将会被合并为一个数组,同名钩子函数会依次执行。其实可以将钩子函数看做一个订阅事件,当此事件被多次订阅后,肯定也会多次执行。

var mixin = {
  created: function () {
    console.log('混入对象的钩子被调用')
  }
}
new Vue({
  mixins: [mixin],
  created: function () {
    console.log('组件钩子被调用')
  }
})
// => "混入对象的钩子被调用"
// => "组件钩子被调用"

值为对象的选项,例如methodscomponentsdirectives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。与data合并方式类似。Vue.extend()也是如此。

var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}

var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    conflicting: function () {
      console.log('from self')
    }
  }
})

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

全局混入:我们可以使用Vue.mixin({})进行全局混入,当使用全局混入时,以后使用的每一个vue实例都会受到此影响(包括第三方组件),所有不建议使用。

23.自定义指令

全局定义时,可以使用Vue.directive('directive-name', {})进行定义;当然也可以在组件内使用局部定义directives属性。

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
// 局部定义
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

定义时,需要定义指令的触发时间,也就是指令的钩子函数:
bind: 只调用一次,指令第一次绑定到元素时调用。
insert: 被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated: 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind: 只调用一次,指令与元素解绑时调用。

钩子函数的参数请参考vue文档。