【vue2】基础

介绍

Vue.js 是什么
Vue 是一套用于构建用户界面的渐进式框架
vue2文档:文档链接

注意:Vue 2 已经终止支持且不再维护。

一、安装

1、CDN
对于学习,你可以这样使用最新版本:

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

对于生产环境,推荐链接到一个明确的版本号:

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>

2、NPM
最新稳定版:

npm install vue@^2

二、Vue 实例

1、创建 Vue 实例

var vm = new Vue({
  // 选项
})

2、生命周期

生命周期图示
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等

  • beforeCreate(创建前)

    vue 实例还没有被完全创建出来,此时 data,methods 等内部没有初始化,无法获取响应数据

  • created(创建后)

    实例创建完成,data、methods等都配置完成,可以访问data中的属性,但是渲染节点还未挂载到DOM,不能访问$el

  • beforeMount(挂载前):

    挂载之前调用,相关的render函数首次调用。实例完成一下配置:编译模版,把data里面的数据和模板生成html。还未挂载到html

  • mounted(挂载后):

    创建阶段完成,页面渲染完毕,进入运行阶段。此时我们可以通过$ refs 来访问到真实的DOM 结构,即可以访问 dom 节点。ref 类似与 id 一样 值必须是唯一的,访问的时候我们可以使用this.$refs.属性,可以进行用户交互操作方法。

  • beforeUpdate(更新前)

    内存中的数据已经改变,页面上的还没更新

  • updated(更新后)

    页面上数据和内存中的一致

  • beforeDestroy(销毁前)

    触发这个函数时,还没开始销毁,此时刚刚脱离运行阶段。data,methods,指令之类的都在正常运行。用于移除 dom 事件监听、定时器等。

  • destroyed(销毁后)

    组件销毁完毕,data,methods,指令之类的不可用

var vm = new Vue({
  el: '#app',
  data: {
    message: 'vue 实例',
  },

  beforeCreate: function () {
    console.log('beforeCreate');
  },
  created: function () {
    console.log('created');
  },

  beforeMount: function () {
    console.log('beforeMount');
  },
  mounted: function () {
    console.log('mounted');
  },

  beforeUpdate: function () {
    console.log('beforeUpdate');
  },
  updated: function () {
    console.log('updated');
  },

  beforeDestroy: function () {
    console.log('beforeDestroy');
  },
  destroyed: function() {
    console.log('destroyed');
  }
});

三、模版语法

1、插值

1.1 文本
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

<span>Message: {{ msg }}</span>

1.2 原始 HTML
为了输出真正的 HTML,你需要使用 v-html 指令:

<p>Using v-html directive: <span v-html="rawHtml"></span></p>

这个 span 的内容将会被替换成为 property 值 rawHtml

1.3 属性 Attribute
Mustache 语法不能作用在 HTML attribute 上,遇到这种情况应该使用 v-bind 指令:

<div v-bind:id="dynamicId"></div>

对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中:

<button v-bind:disabled="isButtonDisabled">Button</button>

如果 isButtonDisabled 的值是 null、undefined 或 false,则 disabled attribute 甚至不会被包含在渲染出来的 元素中。

1.4 使用 JavaScript 表达式
Vue.js 都提供了完全的 JavaScript 表达式支持

<p>{{ number + 1 }}</p>
<p>{{ flag ? 'ok' : 'no' }}</p>
<div v-bind:id="'list-' + id"></div>

2、指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

比如:

<p v-if="seen">现在你看到我了</p>

2.1 参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示
如:v-bind:

<a v-bind:href="url">...</a>

v-on:

<a v-on:click="doSomething">...</a>

2.2 动态参数
从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:
比如:

<a v-bind:[attributeName]="url"> ... </a>

2.3 修饰符

修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定

如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():

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

3、缩写

3.1 v-bind 缩写:
使用冒号代替:

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>

3.1 v-on 缩写
使用@代替

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>

四、计算属性和监听器

1、计算属性 computed

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的,所以,对于任何复杂逻辑,你都应当使用计算属性

特点:
计算属性是基于它们的响应式依赖进行缓存的

1.1 基本使用

示例:

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

结果:

hello
olleh

当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新

1.2 计算属性缓存 vs 方法

通过表达式调用方法reversedMessage()来也能达到同样的效果

<div id="app">
    <p>{{ message }}</p>
    <p>{{ reversedMessage() }}</p>
</div>
var vm = new Vue({
    el: '#app',
    data: {
      message: 'hello'
    },

    methods: {
      // 计算属性的 gettter
      reversedMessage: function() {
        return this.message.split('').reverse().join('');
      }
    }
});

不同的是:
计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数

比如下面使用方法的,3次访问reversedMessage就要执行3次函数:

<div id="app">
    <p>{{ message }}</p>
    <p>{{ reversedMessage() }}</p>
  	<p>{{ reversedMessage() }}</p>
  	<p>{{ reversedMessage() }}</p>
</div>

而计算属性会立即返回之前的计算结果,不必再次执行函数:

<div id="app">
    <p>{{ message }}</p>
    <p>{{ reversedMessage }}</p>
  	<p>{{ reversedMessage }}</p>
  	<p>{{ reversedMessage }}</p>
</div>

1.3 计算属性的 setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter

如下:
运行 vm.fullName = “hello world” 时,setter会被调用

var vm = new Vue({
    el: '#app',
    data: {
        firstName: 'Foo',
        lastName: 'Bar',
    },

    computed: {
        fullName: {
            get: function () {
                return this.firstName + ' ' + this.lastName;
            },
            set: function(newVal) {
                console.log(newVal);
                var names = newVal.split(' ');
                this.firstName = names[0];
                this.lastName = names[1];
            }
        }
    }
});

2、侦听器 watch

当需要在数据变化时执行异步或开销较大的操作时,这个方式最有用

2.1 基本使用

示例:

<div id="app">
    <input v-model="nameInput">
    <p>你输入的内容是:{{ message }}</p>
</div>
var vm = new Vue({
    el: '#app',
    data: {
        nameInput: '',
        message: '等待输入内容...',
    },

    created: function () {
        this.debounceGetMessage = debounce(this.getMessage);
    },

    methods: {
        getMessage: function () {
            this.message = this.nameInput;
        }
    },

    watch: {
        nameInput: function () {
            this.message = '输入中...';
            this.debounceGetMessage();
        }
    }
});

// 防抖
function debounce(func) {
    let timer;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(function () {
            func();
        }, 500);
    }
}

2.2 计算属性 vs 侦听属性

侦听属性:用来观察和响应 Vue 实例上的数据变动

例子:

<div id="app">
    <p>{{ fullName }}</p>
</div>

侦听属性版本:

var vm = new Vue({
  el: '#app',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },

  watch: {
    firstName: function(val) {
      this.fullName = val + ' ' + this.lastName; 
    },
    lastName: function(val) {
      this.fullName = this.firstName + ' ' + val;
    }
  }
});

如上代码是重复式的,与计算属性版本比较

var vm = new Vue({
  el: '#app',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
  },

  computed: {
    fullName: function() {
      return this.firstName + ' ' + this.lastName;
    }
  }
});

这样就好多了

五、Class 与 Style 绑定

1、绑定 class

1.1 对象语法
(1)我们可以传给 v-bind:class 一个对象,以动态地切换 class:

<div v-bind:class="{ active: isActive }"></div>

active 这个 class 存在是否取决于 isAcitve

(2)可以与普通的 class attribute 共存:
如:

<div
  class="static"
  v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
	isAcitve: true
}

渲染为:

<div class="static active"></div>

(3)绑定的数据对象不必内联定义在模板里:

<div v-bind:class="classObject"></div>
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

(4)也可以在这里绑定一个返回对象的计算属性

<div v-bind:class="classObject"></div>
data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

1.2 数组语法
(1)可以把一个数组传给 v-bind:class

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

渲染为:

<div class="active text-danger"></div>

(2)如果你也想根据条件切换列表中的 class,可以用三元表达式:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

(3)在数组语法中也可以使用对象语法:

<div v-bind:class="[{ active: isActive }, errorClass]"></div>

1.3 用在组件上

当在一个自定义组件上使用 class property 时,这些 class 将被添加到该组件的根元素上面。
这个元素上已经存在的 class 不会被覆盖。

(1)例如,声明了这个组件:

Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})

然后在使用它的时候添加一些 class:

<my-component class="baz boo"></my-component>

HTML 将被渲染为:

<p class="foo bar baz boo">Hi</p>

(2)对于带数据绑定 class 也同样适用:

<my-component v-bind:class="{ active: isActive }"></my-component>

当 isActive 为 truthy时,HTML 将被渲染成为:

<p class="foo bar active">Hi</p>

2、绑定内联样式 Style

2.1 对象语法
v-bind:style
(1)CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
  activeColor: 'red',
  fontSize: 30
}

(2)直接绑定到一个样式对象通常更好,这会让模板更清晰:

<div v-bind:style="styleObject"></div>
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

2.2 数组语法
v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:

<div v-bind:style="[baseStyles, overridingStyles]"></div>

2.3 自动添加前缀
当 v-bind:style 使用需要添加浏览器引擎前缀 (opens new window)的 CSS property 时,如 transform,Vue.js 会自动侦测并添加相应的前缀

2.4 多重值
从 2.3.0 起你可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,
例如:

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex

六、条件渲染

1、v-if、v-else、v-if-else

v-if 指令用于条件性地渲染一块内容。
这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
示例1:(v-if)

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

示例2:(v-else)
也可以用 v-else 添加一个“else 块”:

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

示例3:(v-if-else)

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

1.2、在<template>元素上使用 v-if 条件渲染分组
如果想切换多个元素,可以使用 <template>

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

2、v-show

另一个用于根据条件展示元素的选项是 v-show 指令

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。
v-show 只是简单地切换元素的 CSS property display

用法:

<h1 v-show="ok">Hello!</h1>

3、v-if 和 v-show 的对比

  1. v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
  2. v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
  3. 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换

总结:
4. 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
5. 如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

七、列表渲染

1、v-for (数组)

  • 用 v-for 指令基于一个数组来渲染一个列表
  • v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

示例:

<ul id="example-1">
  <li v-for="item in items" :key="item.message">
    {{ item.message }}
  </li>
</ul>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

v-for 还支持一个可选的第二个参数,即当前项的索引:

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

也可以用 of 替代 in 作为分隔符:

<div v-for="item of items"></div>

2、v-for(对象)

你也可以用 v-for 来遍历一个对象的 property。

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
data: {
  object: {
    title: 'How to do lists in Vue',
      author: 'Jane Doe',
        publishedAt: '2016-04-10'
  }
}

你也可以提供第二个的参数为 property 名称 (也就是键名):

<div v-for="(value, name) in object">
  {{ name }}: {{ value }}
</div>

3、维护状态(key)

  • 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute,建议尽可能在使用 v-for 时提供 key attribute
  • 不要使用对象或数组之类的非基本类型值作为 v-for 的 key。
  • 请用字符串或数值类型的值
<div v-for="item in items" v-bind:key="item.id">
  <!-- 内容 -->
</div>

4、数组更新检测

4.1 变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

4.2 替换数组
非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。
当使用非变更方法时,可以用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

5、显示过滤/排序后的结果

可以创建一个计算属性,来返回过滤或排序后的数组。

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

6、在 v-for 里使用范围值

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

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

7、在 <template> 上使用 v-for

可以利用带有 v-for 的 来循环渲染一段包含多个元素的内容:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

8、v-for 与 v-if 一同使用

注意我们不推荐在同一元素上使用 v-if 和 v-for,当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中
当你只想为部分项渲染节点时,这种优先级的机制会十分有用,如下:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

上面的代码将只渲染未完成的 todo

而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 ) 上。如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

9、在组件上使用 v-for

在自定义组件上,你可以像在任何普通元素上一样使用 v-for

<my-component v-for="item in items" :key="item.id"></my-component>

然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。
为了把迭代数据传递到组件里,我们要使用 prop

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>

八、事件处理

1、监听事件

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

<div id="example-1">
  <button v-on:click="counter += 1">Add 1</button>
  <p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
  el: '#example-1',
  data: {
    counter: 0
  }
})

2、事件处理方法

v-on 还可以接收一个需要调用的方法名称

<div id="example-2">
  <!-- `greet` 是在下面定义的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 对象中定义方法
  methods: {
    greet: function (event) {
      // `this` 在方法里指向当前 Vue 实例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

3、内联处理器中的方法

除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:

<div id="example-3">
  <button v-on:click="say('hi')">Say hi</button>
  <button v-on:click="say('what')">Say what</button>
</div>
new Vue({
  el: '#example-3',
  methods: {
    say: function (message) {
      alert(message)
    }
  }
})

有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:

<button v-on:click="warn('这是参数1', $event)">
  	Submit
</button>

4、事件修饰符

修饰符是由点开头的指令后缀来表示的:

  • .stop
    阻止了事件冒泡,相当于调用了event.stopPropagation方法

    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
  • .prevent
    阻止了事件的默认行为,相当于调用了event.preventDefault方法

    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
  • .capture
    使事件触发从包含这个元素的顶层开始往下触发

    <div v-on:click.capture="capture(1)">
        按钮1
        <div v-on:click.capture="capture(2)">
            按钮2
            <div v-on:click.capture="capture(3)">
                按钮3
            </div>
        </div>
    </div>
    
    methods: {
        capture: function(num){
            console.log('执行序号:', num);
        }
    }
    

    点击按钮3,执行结果

    执行序号: 1
    执行序号: 2
    执行序号: 3
    

    不加capture:

    执行序号: 3
    执行序号: 2
    执行序号: 1
    
  • .self
    只当在 event.target 是当前元素自身时触发处理函数

    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="parent">
        <button v-on:click="doThis">按钮</button>
    </div>
    
    methods: {
        parent: function() {
            console.log('父级');
        },
        doThis: function() {
            console.log('子级');
        }
    }
    

    此时parent事件不会触发

  • .once
    点击事件将只会触发一次

    <!-- 点击事件将只会触发一次 -->
    <a v-on:click.once="doThis"></a>
    
  • .passive
    在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符

    <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
    <!-- 而不会等待 `onScroll` 完成  -->
    <!-- 这其中包含 `event.preventDefault()` 的情况 -->
    <div v-on:scroll.passive="onScroll">...</div>
    

5、按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

按键码
使用 keyCode attribute 也是允许的:

<input v-on:keyup.13="submit">

Vue 提供了绝大多数常用的按键码的别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名 (opens new window):

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

6、系统修饰键

  • 可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
    • .ctrl
    • .alt
    • .shift
    • .meta
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>

注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。

.exact 修饰符

  • .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
    <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
    <button v-on:click.ctrl="onClick">A</button>
    
    <!-- 有且只有 Ctrl 被按下的时候才触发 -->
    <button v-on:click.ctrl.exact="onCtrlClick">A</button>
    
    <!-- 没有任何系统修饰符被按下的时候才触发 -->
    <button v-on:click.exact="onClick">A</button>
    

鼠标按键修饰符

  • 这些修饰符会限制处理函数仅响应特定的鼠标按钮
    • .left
    • .right
    • .middle

九、表单输入绑定

可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定
它会根据控件类型自动选取正确的方法来更新元素

1、基础用法

(1)文本

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

(2)多行文本

<textarea v-model="message" placeholder="add multiple lines"></textarea>

(3)复选框
单个复选框:

<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>

多个复选框:

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
new Vue({
  el: '...',
  data: {
    checkedNames: []
  }
})

(4)单选按钮

<div id="example-4">
  <input type="radio" id="one" value="One" v-model="picked">
  <label for="one">One</label>
  <br>
  <input type="radio" id="two" value="Two" v-model="picked">
  <label for="two">Two</label>
  <br>
  <span>Picked: {{ picked }}</span>
</div>
new Vue({
  el: '#example-4',
  data: {
    picked: ''
  }
})

(5)选择框
单选:

<div id="example-5">
  <select v-model="selected">
    <option disabled value="">请选择</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})

多选时 (绑定到一个数组):

<div id="example-6">
  <select v-model="selected" multiple style="width: 50px;">
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <br>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '#example-6',
  data: {
    selected: []
  }
})

用 v-for 渲染的动态选项:

<select v-model="selected">
  <option v-for="option in options" v-bind:value="option.value">
    {{ option.text }}
  </option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
  el: '...',
  data: {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' },
      { text: 'Three', value: 'C' }
    ]
  }
})

2、值绑定

有时我们可能想把值绑定到 Vue 实例的一个动态 property 上,这时可以用 v-bind 实现,并且这个 property 的值可以不是字符串
(1)复选框

<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'

(2)单选按钮

<input type="radio" v-model="pick" v-bind:value="a">
// 当选中时
vm.pick === vm.a

(3)选择框的选项

<select v-model="selected">
    <!-- 内联对象字面量 -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>
// 当选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123

3、修饰符

(1).lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步。
你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">

(2).number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<input v-model.number="age" type="number">

这通常很有用,因为即使在 type=“number” 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值

(3).trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

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

十、组件基础

  • 组件是可复用的 Vue 实例,且带有一个名字(如下面的<button-counter>
  • 它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

1、基本示例

示例:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

2、组件的复用

可以将组件进行任意次数的复用:

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

data 必须是一个函数
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
  return {
    count: 0
  }
}

3、通过 Prop 向子组件传递数据

  • Prop 是你可以在组件上注册的一些自定义 attribute
  • 我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:
    示例1:
Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传递进来:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>

示例2:
可以使用 v-bind 来动态传递 prop:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

4、单个根元素

每个组件必须只有一个根元素:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

5、监听子组件事件

父级组件可以通过 v-on 监听子组件实例的任意事件:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

同时子组件可以通过调用内建的**$emit** 方法并传入事件名称来触发一个事件:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

6、使用事件抛出一个值

可以使用 $emit 的第二个参数来提供抛出的值:

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

然后当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

或者,如果这个事件处理函数是一个方法:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>
methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

7、在组件上使用 v-model

自定义事件也可以用于创建支持 v-model 的自定义输入组件:
首先:

<input v-model="searchText">

等价于:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

使用步骤:

  • 将其 value attribute 绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出

示例:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

现在组件上使用 v-model :

<custom-input v-model="searchText"></custom-input>

8、插槽<slot>

当需要向一个组件传递内容,可以使用Vue 自定义的<slot>元素:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})
<alert-box>
  Something bad happened.
</alert-box>

渲染结果:

Error! Something bad happened.

9、动态组件

有的时候,需要在不同组件之间进行动态切换,可以通过 Vue 的 <component> 元素加一个特殊的 is attribute 来实现:

<div id="app">
    <button v-for="tab in tabs" v-bind:key="tab"
        v-on:click="currentTab = tab">
        {{ tab }}
    </button>
  
    <component v-bind:is="currentTabComponent" class="tab"></component>
</div>
Vue.component("tab-home", {
    template: "<div>Home component</div>"
});
Vue.component("tab-posts", {
    template: "<div>Posts component</div>"
});
Vue.component("tab-archive", {
    template: "<div>Archive component</div>"
});

var vm = new Vue({
    el: '#app',
    data: {
        currentTab: "Home",
        tabs: ["Home", "Posts", "Archive"]
    },
    computed: {
        currentTabComponent: function () {
            return "tab-" + this.currentTab.toLowerCase();
        }
    }
});

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或
  • 一个组件的选项对象
  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值