Skip to content

Vue2 指令 ​

内置指令总览 ​

指令作用简写
v-text更新元素文本内容-
v-html更新元素 HTML 内容-
v-show切换 display 控制显隐-
v-if / v-else-if / v-else条件渲染(惰性)-
v-for列表渲染-
v-on绑定事件监听@
v-bind动态绑定属性:
v-model表单双向绑定-
v-cloak解决插值表达式闪烁-
v-once只渲染一次-
v-pre跳过编译,提升性能-

条件渲染 ​

v-if / v-else-if / v-else ​

vue
<template>
  <div>
    <h1 v-if="score >= 90">优秀</h1>
    <h1 v-else-if="score >= 60">及格</h1>
    <h1 v-else>不及格</h1>
  </div>
</template>
<template>
  <div>
    <h1 v-if="score >= 90">优秀</h1>
    <h1 v-else-if="score >= 60">及格</h1>
    <h1 v-else>不及格</h1>
  </div>
</template>
  • v-if 是"真正"的条件渲染,条件为假时元素不会被渲染
  • v-else-if 和 v-else 必须紧跟在 v-if 之后

v-show ​

vue
<template>
  <h1 v-show="isVisible">我可能显示也可能隐藏</h1>
</template>
<template>
  <h1 v-show="isVisible">我可能显示也可能隐藏</h1>
</template>
  • v-show 只是切换 display 属性,元素始终渲染
  • 不适合 template 标签使用

v-if vs v-show ​

特性v-ifv-show
渲染方式条件为假时不渲染 DOM始终渲染,切换 display
切换开销高(销毁/重建)低(切换 CSS)
初始开销低(条件为假时不渲染)高(始终渲染)
适用场景运行时条件变化少的场景频繁切换显隐的场景

列表渲染 ​

v-for 基本用法 ​

vue
<template>
  <div>
    <!-- 遍历数组 -->
    <li v-for="(item, index) in items" :key="item.id">
      {{ index }} - {{ item.name }}
    </li>

    <!-- 遍历对象 -->
    <li v-for="(value, key, index) in obj" :key="key">
      {{ index }} - {{ key }}: {{ value }}
    </li>

    <!-- 遍历数字 -->
    <li v-for="n in 10" :key="n">{{ n }}</li>
  </div>
</template>
<template>
  <div>
    <!-- 遍历数组 -->
    <li v-for="(item, index) in items" :key="item.id">
      {{ index }} - {{ item.name }}
    </li>

    <!-- 遍历对象 -->
    <li v-for="(value, key, index) in obj" :key="key">
      {{ index }} - {{ key }}: {{ value }}
    </li>

    <!-- 遍历数字 -->
    <li v-for="n in 10" :key="n">{{ n }}</li>
  </div>
</template>

key 的重要性 ​

Vue 通过 key 追踪每个节点的身份,用于高效的 DOM 复用和重新排序。

vue
<template>
  <div>
    <!-- 建议使用唯一 id,而非 index -->
    <li v-for="(item, index) in items" :key="item.id">
      {{ item.name }}
    </li>
  </div>
</template>
<template>
  <div>
    <!-- 建议使用唯一 id,而非 index -->
    <li v-for="(item, index) in items" :key="item.id">
      {{ item.name }}
    </li>
  </div>
</template>

不使用 index 作为 key 的原因: 当列表顺序变化或被删除时,index 会变化,导致 Vue 无法正确复用或重排元素。

数组更新检测 ​

Vue2 只能检测到以下数组变更方法:

js
// 会触发视图更新
this.items.push(item)
this.items.pop()
this.items.shift()
this.items.unshift(item)
this.items.splice(index, 1, newItem)
this.items.sort((a, b) => a - b)
this.items.reverse()

// 不会触发视图更新
this.items[index] = newValue      // 需要用 this.$set
this.items.length = newLength     // 需要用 this.items.splice(newLength)
// 会触发视图更新
this.items.push(item)
this.items.pop()
this.items.shift()
this.items.unshift(item)
this.items.splice(index, 1, newItem)
this.items.sort((a, b) => a - b)
this.items.reverse()

// 不会触发视图更新
this.items[index] = newValue      // 需要用 this.$set
this.items.length = newLength     // 需要用 this.items.splice(newLength)

事件处理 ​

v-on 基础用法 ​

vue
<template>
  <div>
    <!-- 绑定事件 -->
    <button v-on:click="handleClick">点击</button>
    <button @click="handleClick">点击(简写)</button>

    <!-- 传参 -->
    <button @click="say('hello', $event)">传参</button>

    <!-- 内联语句 -->
    <button @click="count++">+1</button>
    <button @click="show = !show">切换</button>

    <!-- 动态事件名 -->
    <button @[eventName]="handleClick">动态事件</button>
  </div>
</template>

<script>
export default {
  data() {
    return { eventName: 'click', count: 0, show: false }
  },
  methods: {
    handleClick(event) {
      console.log('点击了', event.target)
    },
    say(msg, event) {
      console.log(msg, event)
    }
  }
}
</script>
<template>
  <div>
    <!-- 绑定事件 -->
    <button v-on:click="handleClick">点击</button>
    <button @click="handleClick">点击(简写)</button>

    <!-- 传参 -->
    <button @click="say('hello', $event)">传参</button>

    <!-- 内联语句 -->
    <button @click="count++">+1</button>
    <button @click="show = !show">切换</button>

    <!-- 动态事件名 -->
    <button @[eventName]="handleClick">动态事件</button>
  </div>
</template>

<script>
export default {
  data() {
    return { eventName: 'click', count: 0, show: false }
  },
  methods: {
    handleClick(event) {
      console.log('点击了', event.target)
    },
    say(msg, event) {
      console.log(msg, event)
    }
  }
}
</script>

事件修饰符 ​

vue
<template>
  <div>
    <!-- 阻止冒泡 -->
    <button @click.stop="doThis">停止冒泡</button>

    <!-- 阻止默认行为 -->
    <form @submit.prevent="onSubmit">阻止提交</form>

    <!-- 串联修饰符 -->
    <button @click.stop.prevent="doThis">串联</button>

    <!-- 只当点击元素本身触发 -->
    <div @click.self="doThat">self</div>

    <!-- 事件捕获模式 -->
    <div @click.capture="doThis">捕获</div>

    <!-- 只触发一次 -->
    <button @click.once="doThis">只触发一次</button>

    <!-- 组件上监听原生事件 -->
    <custom-component @click.native="handleClick">原生事件</custom-component>
  </div>
</template>
<template>
  <div>
    <!-- 阻止冒泡 -->
    <button @click.stop="doThis">停止冒泡</button>

    <!-- 阻止默认行为 -->
    <form @submit.prevent="onSubmit">阻止提交</form>

    <!-- 串联修饰符 -->
    <button @click.stop.prevent="doThis">串联</button>

    <!-- 只当点击元素本身触发 -->
    <div @click.self="doThat">self</div>

    <!-- 事件捕获模式 -->
    <div @click.capture="doThis">捕获</div>

    <!-- 只触发一次 -->
    <button @click.once="doThis">只触发一次</button>

    <!-- 组件上监听原生事件 -->
    <custom-component @click.native="handleClick">原生事件</custom-component>
  </div>
</template>

按键修饰符 ​

vue
<template>
  <div>
    <!-- 回车键 -->
    <input @keyup.enter="submit">

    <!-- 组合键 -->
    <input @keyup.ctrl.enter="submitWithCtrl">

    <!-- 常用按键别名 -->
    <!-- .enter / .tab / .delete / .esc / .space / .up / .down / .left / .right -->
  </div>
</template>
<template>
  <div>
    <!-- 回车键 -->
    <input @keyup.enter="submit">

    <!-- 组合键 -->
    <input @keyup.ctrl.enter="submitWithCtrl">

    <!-- 常用按键别名 -->
    <!-- .enter / .tab / .delete / .esc / .space / .up / .down / .left / .right -->
  </div>
</template>

系统修饰键 ​

vue
<template>
  <div>
    <!-- 按住 ctrl 点击 -->
    <button @click.ctrl="doSomething">Ctrl + Click</button>

    <!-- 同时按下 alt + c -->
    <input @keyup.alt.67="clear">

    <!-- 修饰键:ctrl / alt / shift / meta -->
  </div>
</template>
<template>
  <div>
    <!-- 按住 ctrl 点击 -->
    <button @click.ctrl="doSomething">Ctrl + Click</button>

    <!-- 同时按下 alt + c -->
    <input @keyup.alt.67="clear">

    <!-- 修饰键:ctrl / alt / shift / meta -->
  </div>
</template>

鼠标修饰符 ​

vue
<template>
  <button @click.left="leftClick">鼠标左键</button>
  <button @click.right="rightClick">鼠标右键</button>
  <button @click.middle="middleClick">鼠标中键</button>
</template>
<template>
  <button @click.left="leftClick">鼠标左键</button>
  <button @click.right="rightClick">鼠标右键</button>
  <button @click.middle="middleClick">鼠标中键</button>
</template>

属性绑定 ​

v-bind 基础 ​

vue
<template>
  <div>
    <!-- 绑定属性 -->
    <img v-bind:src="imageSrc" :alt="altText">

    <!-- 动态属性名 -->
    <button :[key]="value">动态属性</button>

    <!-- 绑定对象 -->
    <div v-bind="{ id: someId, 'data-type': type }">对象绑定</div>
  </div>
</template>
<template>
  <div>
    <!-- 绑定属性 -->
    <img v-bind:src="imageSrc" :alt="altText">

    <!-- 动态属性名 -->
    <button :[key]="value">动态属性</button>

    <!-- 绑定对象 -->
    <div v-bind="{ id: someId, 'data-type': type }">对象绑定</div>
  </div>
</template>

动态样式 ​

动态 class ​

vue
<template>
  <div>
    <!-- 对象语法 -->
    <div :class="{ active: isActive, 'text-danger': hasError }"></div>

    <!-- 数组语法 -->
    <div :class="[activeClass, errorClass]"></div>

    <!-- 三元表达式 -->
    <div :class="[isActive ? 'active' : '']"></div>

    <!-- 数组+对象混合 -->
    <div :class="[{ active: isActive }, 'static-class']"></div>

    <!-- 绑定到组件的根元素上 -->
    <custom-component class="custom-class"></custom-component>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isActive: true,
      hasError: false,
      activeClass: 'active',
      errorClass: 'text-danger'
    }
  }
}
</script>
<template>
  <div>
    <!-- 对象语法 -->
    <div :class="{ active: isActive, 'text-danger': hasError }"></div>

    <!-- 数组语法 -->
    <div :class="[activeClass, errorClass]"></div>

    <!-- 三元表达式 -->
    <div :class="[isActive ? 'active' : '']"></div>

    <!-- 数组+对象混合 -->
    <div :class="[{ active: isActive }, 'static-class']"></div>

    <!-- 绑定到组件的根元素上 -->
    <custom-component class="custom-class"></custom-component>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isActive: true,
      hasError: false,
      activeClass: 'active',
      errorClass: 'text-danger'
    }
  }
}
</script>

动态 style ​

vue
<template>
  <div>
    <!-- 对象语法 -->
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

    <!-- 数组语法(多个样式对象) -->
    <div :style="[baseStyles, overridingStyles]"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      activeColor: 'red',
      fontSize: 16,
      baseStyles: { color: 'red', fontSize: '14px' },
      overridingStyles: { fontWeight: 'bold' }
    }
  }
}
</script>
<template>
  <div>
    <!-- 对象语法 -->
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

    <!-- 数组语法(多个样式对象) -->
    <div :style="[baseStyles, overridingStyles]"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      activeColor: 'red',
      fontSize: 16,
      baseStyles: { color: 'red', fontSize: '14px' },
      overridingStyles: { fontWeight: 'bold' }
    }
  }
}
</script>

表单绑定 ​

v-model 基础 ​

vue
<template>
  <div>
    <!-- 文本输入 -->
    <input v-model="message" placeholder="输入文字">
    <p>{{ message }}</p>

    <!-- 多行文本 -->
    <textarea v-model="content"></textarea>

    <!-- 复选框 -->
    <input type="checkbox" v-model="checked">
    <div>选中:{{ checked }}</div>

    <!-- 多选复选框 -->
    <input type="checkbox" value="A" v-model="hobbies">
    <input type="checkbox" value="B" v-model="hobbies">
    <input type="checkbox" value="C" v-model="hobbies">

    <!-- 单选框 -->
    <input type="radio" value="男" v-model="gender">
    <input type="radio" value="女" v-model="gender">

    <!-- 下拉选择 -->
    <select v-model="selected">
      <option disabled value="">请选择</option>
      <option value="A">A</option>
      <option value="B">B</option>
    </select>

    <!-- 多选下拉 -->
    <select v-model="selectedList" multiple>
      <option v-for="item in options" :key="item.value" :value="item.value">
        {{ item.text }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
      content: '',
      checked: false,
      hobbies: [],
      gender: '',
      selected: '',
      selectedList: [],
      options: [
        { text: '选项A', value: 'A' },
        { text: '选项B', value: 'B' }
      ]
    }
  }
}
</script>
<template>
  <div>
    <!-- 文本输入 -->
    <input v-model="message" placeholder="输入文字">
    <p>{{ message }}</p>

    <!-- 多行文本 -->
    <textarea v-model="content"></textarea>

    <!-- 复选框 -->
    <input type="checkbox" v-model="checked">
    <div>选中:{{ checked }}</div>

    <!-- 多选复选框 -->
    <input type="checkbox" value="A" v-model="hobbies">
    <input type="checkbox" value="B" v-model="hobbies">
    <input type="checkbox" value="C" v-model="hobbies">

    <!-- 单选框 -->
    <input type="radio" value="男" v-model="gender">
    <input type="radio" value="女" v-model="gender">

    <!-- 下拉选择 -->
    <select v-model="selected">
      <option disabled value="">请选择</option>
      <option value="A">A</option>
      <option value="B">B</option>
    </select>

    <!-- 多选下拉 -->
    <select v-model="selectedList" multiple>
      <option v-for="item in options" :key="item.value" :value="item.value">
        {{ item.text }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
      content: '',
      checked: false,
      hobbies: [],
      gender: '',
      selected: '',
      selectedList: [],
      options: [
        { text: '选项A', value: 'A' },
        { text: '选项B', value: 'B' }
      ]
    }
  }
}
</script>

表单修饰符 ​

vue
<template>
  <div>
    <!-- .lazy:在 change 事件时同步(而非 input 事件) -->
    <input v-model.lazy="message">

    <!-- .number:自动转为数字 -->
    <input v-model.number="age" type="number">

    <!-- .trim:去除首尾空格 -->
    <input v-model.trim="username">
  </div>
</template>
<template>
  <div>
    <!-- .lazy:在 change 事件时同步(而非 input 事件) -->
    <input v-model.lazy="message">

    <!-- .number:自动转为数字 -->
    <input v-model.number="age" type="number">

    <!-- .trim:去除首尾空格 -->
    <input v-model.trim="username">
  </div>
</template>

在组件上使用 v-model ​

vue
<template>
  <!-- 父组件 -->
  <custom-input v-model="searchText"></custom-input>
  <!-- 等价于:<custom-input :value="searchText" @input="searchText = $event"></custom-input> -->
</template>
<template>
  <!-- 父组件 -->
  <custom-input v-model="searchText"></custom-input>
  <!-- 等价于:<custom-input :value="searchText" @input="searchText = $event"></custom-input> -->
</template>
vue
<!-- 子组件 CustomInput.vue -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
  props: ['value']
}
</script>
<!-- 子组件 CustomInput.vue -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
  props: ['value']
}
</script>

自定义组件的 model ​

vue
<script>
// 修改 v-model 默认的 prop 和事件名
export default {
  model: {
    prop: 'checked',   // 默认是 value
    event: 'change'    // 默认是 input
  },
  props: {
    checked: Boolean
  }
}
</script>
<script>
// 修改 v-model 默认的 prop 和事件名
export default {
  model: {
    prop: 'checked',   // 默认是 value
    event: 'change'    // 默认是 input
  },
  props: {
    checked: Boolean
  }
}
</script>

v-cloak ​

解决网速慢时页面显示插值表达式的问题。

css
[v-cloak] {
  display: none;
}
[v-cloak] {
  display: none;
}
vue
<template>
  <div v-cloak>
    {{ message }}
  </div>
</template>
<template>
  <div v-cloak>
    {{ message }}
  </div>
</template>

v-once ​

只渲染一次,数据变化时不会重新渲染。

vue
<template>
  <div>
    <span v-once>初始值:{{ message }}</span>
    <!-- 即使 message 改变,上面的 span 也不会更新 -->
  </div>
</template>
<template>
  <div>
    <span v-once>初始值:{{ message }}</span>
    <!-- 即使 message 改变,上面的 span 也不会更新 -->
  </div>
</template>

v-pre ​

跳过元素及其子元素的编译,直接显示原始内容,可提升编译速度。

vue
<template>
  <span v-pre>{{ 这里的内容不会被编译 }}</span>
</template>
<template>
  <span v-pre>{{ 这里的内容不会被编译 }}</span>
</template>