

## v-on的按键修饰符

### Vue 内置的按键修饰符

通俗一点讲，指的是：监听键盘输入的事件。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。如下：

Vue内置的按键修饰符：

```
    .enter
    .tab
    .delete (捕获 “删除” 和 “退格” 键)
    .esc
    .space
    .up
    .down
    .left
    .right
    1.0.8+版本：支持单字母的按键别名。
```


比如说，`keyup`指的是：键盘（任何键位）抬起时的监听事件。`.enter`指的是：按enter键的按键修饰符。我们把这两个结合起来看看。

**`@keyup.enter`举例**：按enter键后的监听事件

`@keyup.enter="addData"`表示：按住enter键后，执行addData()方法。**全称**是`v-on:key.enter="addData"`。

我们还是拿`01-04`这篇文章中的列表功能来举例。之前是点击“添加”按钮后，列表中会添加一个item。现在要求：在**输入框**中按enter键后，也能添加一个item。

核心代码如下：

```html
	<input type="text" v-model="formData.name" @keyup.enter="addData">
```

注意，如果写成`@keyup="addData"`，效果却是：只要键盘的任何键位打了字（还没来得及按enter键），就会执行addData()方法，这种效果显然不是我们想要的。所以要加上修饰符`.enter`，表示只针对enter键。

### 自定义的按键修饰符

如果我们直接在代码的`<input>`标签里写`@keyup.f2="addData"`，那么，按住「F2键」后，是没有效果的，因为「F2键」不是内置的按键修饰符（如果F2不能验证，你可以试一下F7）。

我们知道，每个按键都有一个键盘码。参考链接：

- [js 里面的键盘事件对应的键码](http://www.cnblogs.com/wuhua1/p/6686237.html)

通过查阅，我们知道了「F2键」的键盘码为`113`，那代码可以这样写：（按住F2键后，执行 addData 方法）

```html
	<input type="text" v-model="formData.name" @keyup.113="addData">
```

虽然键盘码很全，但是不好记呀。于是，接下来，我们给键盘码定义别名。

**自定义全局按键修饰符**：

```
    //自定义全局按键修饰符
    Vue.config.keyCodes.f2 = 113;
```

上方代码的书写位置，与自定义全局过滤器的位置，是并列的。

然后，我们就可以使用键盘码的别名了。

## 自定义全局指令

### 自定义全局指令的举例1

**举例1**：让指定文本框自动获取焦点

如果我们想实现这个例子，原生js的写法是：

```javascript
    //原生js写法：网页一打开，就让指定的输入框自动获取焦点
    document.getElementById('search').focus()
```

代码的位置：

![](http://img.smyhvae.com/20180527_2340.png)

但我们不建议这样做。我们可以通过Vue中的自定义指令来实现这个例子。步骤如下。

（1）使用`Vue.directive()`自定义全局指令：

```javascript

    //自定义全局指令 v-focus：让文本框自动获取焦点
    //参数1：指令的名称。注意，在定义的时候，指令的名称前面，不需要加 v- 前缀；但是：在`调用`的时候，必须在指令名称前 加上 v- 前缀
    //参数2：是一个对象，这个对象身上，有一些指令相关的函数，这些函数可以在特定的阶段，执行相关的操作
    Vue.directive('focus', {
    	//在每个函数中，第一个参数，永远是 el ，表示 被绑定了指令的那个元素，这个 el 参数，是一个原生的JS对象（DOM对象）
        bind: function (el) { // 每当指令绑定到元素上的时候，会立即执行这个 bind 函数，【只执行一次】
            // 在元素 刚绑定了指令的时候，还没有 插入到 DOM中去，这时候，调用 focus 方法没有作用
            //  因为，一个元素，只有插入DOM之后，才能获取焦点
            // el.focus()
        },
        inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候，会执行 inserted 函数【触发1次】
            el.focus()
            // 和JS行为有关的操作，最好在 inserted 中去执行，放置 JS行为不生效
        },
        updated: function (el) {  // 当VNode更新的时候，会执行 updated， 【可能会触发多次】

        }
    })
```

上方的代码中，如果我们把`el.focus()`这行代码写在`bind`方法里，是没有效果的（但不会报错）。没有效果是因为，在执行到`bind`方法的时候，元素还没有插入到dom中去。

由此可以看看出：`bind`、`inserted`、`updated`这三个钩子函数的执行时机不同，且执行的次数有区别。

（2）在指定的文本框上加``：

```html
<input type="text" id="search" v-model="keywords" v-focus>
```

完整版代码如下：

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <div id="app">
        搜索框：
        <input type="text" id="search" v-model="name" v-focus>
    </div>

    <script>

        //自定义全局指令 v-focus，让文本框自动获取焦点
        //参数1：指令的名称。注意，在定义的时候，指令的名称前面，不需要加 v- 前缀；但是：在`调用`的时候，必须在指令名称前 加上 v- 前缀
        //参数2：是一个对象，这个对象身上，有一些指令相关的函数，这些函数可以在特定的阶段，执行相关的操作
        Vue.directive('focus', {
            //在每个函数中，第一个参数，永远是 el ，表示 被绑定了指令的那个元素，这个 el 参数，是一个原生的JS对象（DOM对象）
            bind: function (el) { // 每当指令绑定到元素上的时候，会立即执行这个 bind 函数，【只执行一次】
                // 在元素 刚绑定了指令的时候，还没有 插入到 DOM中去，这时候，调用 focus 方法没有作用
                //  因为，一个元素，只有插入DOM之后，才能获取焦点
                // el.focus()
            },
            inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候，会执行 inserted 函数【触发1次】
                el.focus()
                // 和JS行为有关的操作，最好在 inserted 中去执行，防止 JS行为不生效
            },
            updated: function (el) {  // 当VNode更新的时候，会执行 updated， 【可能会触发多次】
            }
        })

        new Vue({
            el: '#app',
            data: {
                name: 'smyhvae'
            }
        })
    </script>
</body>

</html>

```


### 自定义全局指令：使用钩子函数的第二个binding参数拿到传递的值

**举例2**：设置DOM元素的color样式


参考举例1中的写法，我们可能会这样给DOM元素设置样式：

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <div id="app">
        搜索框：
        <input type="text" id="search" v-model="name" v-color>
    </div>

    <script>

        //自定义全局指令 v-color：设置DOM元素的color属性
        Vue.directive('color', {
            bind: function (el) { // 每当指令绑定到元素上的时候，会立即执行这个 bind 函数，【只执行一次】
                el.style.color = 'red';
            },
            inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候，会执行 inserted 函数【触发1次】
                // 和JS行为有关的操作，最好在 inserted 中去执行，防止 JS行为不生效
                //el.focus()
            },
            updated: function (el) {  // 当VNode更新的时候，会执行 updated， 【可能会触发多次】
            }
        })

        new Vue({
            el: '#app',
            data: {
                name: ''
            }
        })
    </script>
</body>

</html>
```

如上方代码所示，我们自定义了一个指令`v-color`，然后在`input`标签中用上了这个指令，就给元素设置了color属性。但是这个代码有个弊端是：color的属性值在定义指令的时候，被写死了。如何完善呢？我们可以在DOM元素中传参。一起来看看。

代码如下：【荐】

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <div id="app">
        搜索框1：
        <input type="text" id="search" v-model="name" v-color="'green'">
    </div>

    <script>

        //自定义全局指令 v-color：设置DOM元素的color属性
        Vue.directive('color', {
            // 样式，只要通过指令绑定给了元素，不管这个元素有没有被插入到页面中去，这个元素肯定有了一个内联的样式
            // 将来元素肯定会显示到页面中，这时候，浏览器的渲染引擎必然会解析样式，应用给这个元素
            // 意思是说，我们可以把样式的代码写到bind中去（即使这个时候，dom元素还没有被创建）
            bind: function (el, binding) { // 每当指令绑定到元素上的时候，会立即执行这个 bind 函数，【只执行一次】

                console.log(binding.name); //打印结果：color
                console.log(binding.value); //打印结果：green
                console.log(binding.expression);  //'green'

                el.style.color = binding.value// 通过bining拿到v-color中传递过来的值

            },
            inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候，会执行 inserted 函数【触发1次】
                // 和JS行为有关的操作，最好在 inserted 中去执行，防止 JS行为不生效
                //el.focus()
            },
            updated: function (el) {  // 当VNode更新的时候，会执行 updated， 【可能会触发多次】
            }
        })

        new Vue({
            el: '#app',
            data: {
                name: 'smyhvae'
            }
        })
    </script>
</body>

</html>
```

上方代码中,bind方法里传递的第二个参数`binding`，可以拿到DOM元素中`v-color`里填的值。注意，`v-color="'green'"`，这里面写的是字符串常量；如果去掉单引号，就成了变量，不是我们想要的。

效果：

![](http://img.smyhvae.com/20180610_1323.png)

**自定义全局指令的简写形式**：


在很多时候，你可能想在 bind 和 update 时触发相同行为，而不关心其它的钩子。比如上面的代码中，我们可以写成简写形式：

```javascript
        Vue.directive('color', function (el, binding) { //注意，这个function等同于把代码写到了 bind 和 update 中去
            el.style.color = binding.value
        })
```


## 自定义私有指令

**自定义私有指令**：在某一个 vue 对象内部自定义的指令称之为私有指令。这种指令只有在当前vue对象的el指定的监管区域有用。

代码举例：（设置文字的font-weight属性）

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="vue2.5.16.js"></script>
</head>

<body>

    <div id="app">
        <span v-fontweight="600">生命壹号</span>
    </div>
    <script>

        new Vue({
            el: '#app',
            data: {
                name: 'smyhvae'
            },
            //自定义私有指令
            directives: {
                'fontweight': {
                    bind: function (el, binding) {
                        el.style.fontWeight = binding.value;
                    }
                }
            }
        })
    </script>
</body>

</html>
```

效果：

![](http://img.smyhvae.com/20180610_1400.png)

注意， el.style.fontWeight设置属性值，至少要600，否则看不到加粗的效果。

**自定义私有指令的简写形式**：

在很多时候，你可能想在 bind 和 update 时触发相同行为，而不关心其它的钩子。比如上面的代码中，我们可以写成简写形式：

```
            //自定义私有指令（简写形式）
            directives: {
                'fontweight': function (el, binding) { //注意，这个function等同于把代码写到了 bind 和 update 中去
                    el.style.fontWeight = binding.value;
                }
            }
```







