VUE002 Vue Directives
Tags: vue
Published: 2020-12-29 04:50:19

# Vue的指令

指令就是html标签元素中带有`v-`的特殊属性。除了`v-for`，这些属性的值都是单个javascript表达式。当指令的值发生变化时，这些变化会响应式地作用于DOM。

# 常见的Vue指令

- v-show
- v-if
- v-else
- v-for
- v-bind
- v-model
- v-on
- v-cloak

## v-show 与 v-if

`v-show`会根据表达式的真假来切换元素的CSS属性`display`，如果表达式为假，则会给标签加上`style="display: none;"`这条属性。

对于下面的代码：
```html
<div id="app">
  <h1 v-show="12>13">{{ message }}</h1>
</div>
```

在浏览器打开后，`<h1>`标签不会显示，按下F12后，代码如下所示：
```html
<div id="app">
  <h1 style="display: none;">Hello, Vue World!</h1>
</div>
```

`v-if`会根据表达式的真假来渲染元素。

如果上面的例子用`v-if`，则整个`<h1>`标签都不会出现在网页源代码里。

## v-for

基于数据源来对元素进行多次渲染，数据源可以是数组或者对象，`v-for`后面的值依然是一个js表达式，带有这个属性的标签（加上它的子标签）会被循环创建多次。

具体的例子如下：

```html
<body>
  <div id="app">
    <div v-for="item in dataSource">
      Name: {{item.name}}<br>
      Age: {{item.age}}
    </div>
  </div>
</body>

<script>
  var app = new Vue({
    el: '#app',
    data: function () {
      return {
        dataSource: [
          {name: 'Alice', age: 13},
          {name: 'Bob', age: 12},
          {name: 'Carol', age: 12},
          {name: 'Daniel', age: 13},
        ]
      }
    }
  })
</script>
```

渲染后的结果为：
```html
<div id="app">
    <div>
      Name: Alice<br>
      Age: 13
    </div><div>
      Name: Bob<br>
      Age: 12
    </div><div>
      Name: Carol<br>
      Age: 12
    </div><div>
      Name: Daniel<br>
      Age: 13
    </div>
</div>
```

### v-for进阶

除了上述的简单例子，`v-for`还支持一个可选的第二个参数，即当前项的索引。当 Vue 正在更新使用 `v-for` 渲染的元素列表时，它默认使用“就地更新”的策略。如果数据项的顺序被改变，Vue 将不会移动 DOM 元素来匹配数据项的顺序，而是就地更新每个元素，并且确保它们在每个索引位置正确渲染。为了给 Vue 一个提示，以便它能跟踪每个节点的身份，从而重用和重新排序现有元素，我们需要用`v-bind`来为每一个元素指定一个key：

```html
<div id="app">
  <li v-for="(item, index) in dataSource" v-bind:key="index">
    {{ index + 1 }} - {{ item.name }} - {{item.age}} 岁
  </li>
</div>
```

`v-for`也可以用于遍历json对象。比如对于下面这个例子：

```javascript
dataObj: {
  name: "Hue",
  identity: "Fairy",
  age: 3,
  hp: 10938,
  mp: 1080,
  level: 35,
  dps: 2405
}
```

可以这样使用`v-for`：
```html
<li v-for="(val, name, index) in dataObj" v-bind:key="index">
  {{index + 1}} - {{name}} : {{val}}
</li>
```

## v-bind

为一个标签动态绑定一个或者多个属性，或者为一个组件的prop绑定到js表达式。

如果属性是class或style，其值支持数组或对象。其他的属性的值只能是基本数据类型。

```html
<body>
  <div id="app">
     <input type="text" v-bind:placeholder="myPlaceHolder">
     <!-- v-bind:class="{'表达式成立时的类名', 表达式}" -->
     <!-- v-bind:class="['类名1', '类名12', '类名3']" -->
     <button v-bind:class="{'active': 12>11}">Yes</button>
     <button v-bind:class="['active', 'warning']">No</button>
  </div>
</body>

<script>
  var app = new Vue({
    el: '#app',
    data: function () {
      return {
        myPlaceHolder: "Username"
      }
    }
  })
</script>
```

虽然这个例子实用性为零，但是它使得我们仅仅通过修改`myPlaceHolder`的值就可以更改DOM。

`v-bind`可以进一步简写，比如上面的例子中，`v-bind:placeholder`可以简写为`:placeholder`。

## v-model

对表单元素`<input>`，`<textarea>`，`<select>`等元素创建双向绑定，即：

- 数据的变化会影响视图
- 视图的变化会影响数据

具体可以参考官网 https://cn.vuejs.org/v2/guide/forms.html

```html
<body>
  <div id="app">
    <!-- input box 输入框 -->
    <h2>{{ "Hello " + username }}</h2>
    <p>{{ message }}</p>
    <input type="text" v-model="username">
    <br>
    <textarea v-model="message"></textarea>
    <br>
    <!-- selector group 单选 -->
    <input type="radio" value="One" v-model="picked">
    <label>One</label>
    <br>
    <input type="radio" value="Two" v-model="picked">
    <label>Two</label>
    <br>
    <span>Picked: {{ picked }}</span>
    <br>
    <!-- Mutiple selector 多选 -->
    <input type="checkbox" value="Jack" v-model="checkedNames">
    <label>Jack</label>
    <input type="checkbox" value="John" v-model="checkedNames">
    <label>John</label>
    <input type="checkbox" value="Mike" v-model="checkedNames">
    <label>Mike</label>
    <br>
    <span>Checked names: {{ checkedNames }}</span>
  </div>
</body>

<script>
  var app = new Vue({
    el: '#app',
    data: function () {
      return {
        username: "John",
        message: "",
        picked: "",
        checkedNames: []
      }
    }
  })
</script>
```

对于上面的例子，当表单的内容变化时，那些含有`{{  }}`的标签里面的内容也会同步发生变化。

对于单选radio，vue会根据`v-model`绑定的值来决定它们是不是一组。

# v-on

`v-on`的作用是监听DOM事件，并在触发时运行一些JavaScript代码。

官方文档 https://cn.vuejs.org/v2/guide/events.html

比如按钮的点击事件，可以写成`v-on:click`：

```html
<h1>{{message}}</h1>
<button v-on:click="message = message + 's'">change text</button>
```

但是在实际应用中，许多事件处理逻辑会更为复杂，所以直接把 JavaScript 代码写在`v-on`指令中是不可行的。因此`v-on`还可以接收一个需要调用的方法名称。可以在`new Vue()`中传入`methods`参数来定义方法（**`this`对象很关键**）。

```html
<body>
  <div id="app">
     <h1>{{message}}</h1>
     <button v-on:click="changeText">change text</button>
  </div>
</body>

<script>
  var app = new Vue({
    el: '#app',
    data: function () {
      return {
        message: "sfsf"
      }
    },
    methods: {
      changeText: function (event) {
        this.message = this.message + "s";
      }
    }
  })
</script>
```

类似与`v-bind:`可以用`:`替代，`v-on:`可以用`@`替代。上面的`v-on:click`可以简写成`@click`。

更多复杂的使用可以参考官网。

# v-cloak

这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时，这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。

换句话说，`v-cloak`算作一个元素的属性，在页面加载完毕后，这个属性会自动删除。