项目运行
项目初始化
npm install
启动项目
npm run serve
项目打包
npm run build
修复代码样式
npm run lint
用户配置
查看 配置说明.
在 VS Code 中调试
1. 创建vue.config.js文件
module.exports = {
configureWebpack: {
devtool: 'source-map'
}
}
2. 创建launch.json文件
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "vuejs: chrome",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}/src",
"breakOnLoad": true,
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}
]
}
Vue基础
生命周期
- new Vue();
创建Vue对象
- Init Events& Lifecycle
初始化事件,声明周期
- beforeCreate;(hooks)
事件钩子,data:undefind,$el:undefind
- init injection & reactivity
开始注入依赖项目
- created (hooks)
事件钩子,data:{},$el:undefind,初始化props、data、methods、watch、computed完毕
- el检查
是否含有$el,有就继续检查是否含有template,没有则是等待手动调用vm.#mount(el)
- template检查
是否含有template的项目,没有则将$el绑定的outerHTML作为template替换,有则将template编译进render function
- beforeMount (hooks)
事件钩子,data:{},$el:{}, $el里面的样板语言尚未被赋予值进去,所以显示的仍然是两个花括号的部分
- vm.$el创建并更换el
创建vue对象里的属性和方法
- mounted (hooks)
事件钩子,data:{},$el:{}, 一般初始化的Vue组件的必经之路到此阶段就结束了,除了使用keep-alive的组件,keep-alive组件再次渲染时并不会触发created、mounted等hooks
- beforeUpdate (hooks)
事件钩子,数据即将被更新前执行,这个阶段主要可以用在得知哪个组件即将发生数据改动,并且可以移除对其绑定的事件监听。
- updated (hooks)
事件钩子,数据已经更新完毕,重新渲染完成后的状态,在此期间不建议更改状态,如需更改建议使用computed或watch来进行数据更改。
- beforeDestroy (hooks)
事件钩子,实例被销毁前会触发(如透过主动调用vm.$destroy()或是当该元素所绑定的v-if条件变为为false时)。这个阶段我们可以做一些提醒的动作,如是否要保存数据并关闭此窗口等。
- destroyed (hooks)
事件钩子,实例已经被销毁时会触发,销毁意味着所绑定的watcher、child components以及event listeners等已经与原本元素毫无关联了,但要注意的事情是父组件已经渲染在DOM上的视图仍然会保留在页面上,只有子组件会完全消失。
- activated (hooks)
keep-alive事件钩子,当使用keep-alive的组件被渲染时会触发。
- deactivated
keep-alive事件钩子,当使用keep-alive的组件被销毁时会触发这个hook。
模板语法
插值
文本
- 文本插值
html
<span>Message: {{ msg }}</span>
- 单次插值
html
<span v-once>这个将不会改变: {{ msg }}</span>
Attribute
- id绑定
html
<div v-bind:id="dynamicId"></div>
- disabled显示
html
<button v-bind:disabled="isButtonDisabled">Button</button>
JS表达式
javascript
//数字计算
{{ number + 1 }}
//三元表达式
{{ ok ? 'YES' : 'NO' }}
//字符串|数组操作
{{ message.split('').reverse().join('') }}
html
<!-- 在属性中计算 -->
<div v-bind:id="'list-' + id"></div>
指令
参数
html
<!-- v-bind 指令可以用于响应式地更新 HTML attribute -->
<a v-bind:href="url">...</a>
<!-- v-if 插入/移除 <p> 元素 -->
<p v-if="seen">现在你看到我了</p>
<!-- v-on 监听事件 -->
<a v-on:click="doSomething">...</a>
动态参数 2.6.0新增
html
<!-- attributeName 会被作为 JS 表达式动态求值,求得的值将会作为最终的参数使用,如attributeName为href等 -->
<a v-bind:[attributeName]="url"> ... </a>
<!-- eventName为click,focus等 -->
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 不合法,这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value"> ... </a>
<!-- 不合法,someAttr会自动转变为someattr -->
<a v-bind:[someAttr]="value"> ... </a>
修饰符
html
<form v-on:submit.prevent="onSubmit">...</form> <!-- 以半角句号 . 指明的特殊后缀,用于指令特殊方式绑定。.prevent修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault() -->
缩写
html
<!-- v-bind完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
<!-- v-on完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
计算属性
JavaScript
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
//大多数情况,用于监听某个状态,当出现状态更变时,进行网络请求,去刷新最新数据。
watch: {
//监听firstName的变化,变化后执行下面的方法
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
//监听lastName变化,变化后执行下面的方法
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
},
//常用于界面显示转换,本地数据为0|1,显示数据为关|开
computed: {
//当firstName lastName变化时,fullName会自动变化
fullName: function () {
return this.firstName + ' ' + this.lastName
},
//计算属性默认只有 getter,不过在需要时你也可以提供一个 setter: 当 fullName= "aa bb"的时候 set会被调用
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
},
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
},
//常用于按钮事件绑定,网络请求,逻辑模块的编写。
methods: {
//计算属性是基于它们的响应式依赖进行缓存的,可减少计算量,当用户触发无关按钮时,方法就会重新计算一遍,计算属性不会进行计算
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
Class 与 Style 绑定
- 操作元素的 class 列表和内联样式是数据绑定。它们都是 attribute,可以用 v-bind 处理它们。将 v-bind 用于 class 和 style 时,表达式结果的类型 字符串、对象、数组。
绑定 HTML Class
对象语法
html
<div v-bind:class="{ active: isActive }"></div>
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
<script>
//active 这个 class 存在与否将取决于数据 property isActive 的 truthiness。
data(){
return {
//true class有active类 false class没有active类
isActive : true
hasError: false
}
}
//渲染之后
//<div class="active"></div>
//<div class="static active"></div>
</script>
<div v-bind:class="classObject"></div>
<script>
//实际项目之中使用 此种方式较为方便调整。
data: {
classObject: {
active: true,
'text-danger': false
}
}
//渲染之后
//<div class="active"></div>
data: {
isActive: true,
error: null
},
computed: {
//实际项目之中使用 此种方式更加灵活 但是复杂度更高
//通过计算属性 更灵活的设定样式
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
//渲染之后 --
//<div class="active"></div>
</script>
<div v-bind:class="[activeClass, errorClass]"></div>
<script>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
//<div class="active text-danger"></div>
</script>
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
用在组件上
html
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
<my-component class="baz boo"></my-component>
<!-- 渲染结果 -->
<p class="foo bar baz boo">Hi</p>
<my-component v-bind:class="{ active: isActive }"></my-component>
<!-- 渲染结果 -->
<p class="foo bar active">Hi</p>
绑定内联样式
对象语法
- v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。
html
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<div :style="styleObject"></div>
<script>
data: {
activeColor: 'red',
fontSize: 30
}
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
</script>
多重值
- 可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值
html
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
条件渲染
html
<!-- v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。 -->
<!-- if -->
<h1 v-if="awesome">Vue is awesome!</h1>
<!-- if else -->
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
在 < template> 元素上使用 v-if 条件渲染分组
- 多个节点需要进行统一逻辑判断时,< template> 元素当做不可见的包裹元素,并在上面使用 v-if
html
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-else v-else-if
html
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
<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>
用 key 管理可复用的元素
- Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
- 代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素, 不会被替换掉——仅仅是替换了它的 placeholder
html
<!-- input复用 常用语 手机号登录 用户登录切换 -->
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<!-- 独立输入 避免出现切换残留问题-->
<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>
<!-- <label> 元素仍然会被高效地复用 -->
v-show
- v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display
- v-show 不支持 < template > 元素,也不支持 v-else
html
<h1 v-show="ok">Hello!</h1>
v-if vs v-show
- v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
- v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-if 与 v-for 一起使用
- 不推荐同时使用 v-if 和 v-for
- 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
列表渲染
用 v-for 把一个数组对应为一组元素
- v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
html
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
<ul id="v-for-object" class="demo">
<div v-for="(value, name) in object">
{{ name }}: {{ value }}
</div>
</ul>
<script>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
//对index引索的使用
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
</script>
维护状态
- 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
- 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute
- 不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
html
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
数组更新检测
变更方法
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
替换数组
- 变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项
- 由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。深入响应式原理中有相关的讨论。
- array[0] = { title: "变更"} 会检测不到,但是只要在后面执行 array = array.concat(); 就会立即刷新。原理如上述,会当成一个新的数组刷新一遍
显示过滤/排序后的结果
- 创建一个计算属性,来返回过滤或排序后的数组
- 在嵌套 v-for 循环中 你可以使用一个方法
html
<li v-for="n in evenNumbers">{{ n }}</li>
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
<script>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
//过滤不被2整除的值
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
</script>
在 v-for 里使用值范围
- v-for 也可以接受整数。在这种情况下,它会把模板重复对应次数。
html
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
在 < template> 上使用 v-for
html
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
在组件上使用 v-for
- 任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 prop
html
<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<ul>
<!-- <todo-item>会无法识别</todo-item> -->
<li
is="todo-item"
v-for="(todo, index) in todos"
:key="todo.id"
:title="todo.title"
@remove="todos.splice(index, 1)"
></li>
</ul>
</div>
<script>
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button @click="$emit(\'remove\')">Remove</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
</script>
事件处理
监听事件
- v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码
html
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
<script>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
</script>
事件处理方法
html
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button>
</div>
<script>
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)
}
}
}
})
// 也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'
</script>
内联处理器中的方法
html
<div id="example-3">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what')">Say what</button>
</div>
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<script>
new Vue({
el: '#example-3',
methods: {
say: function (message) {
alert(message)
},
warn: function (message, event) {
// 现在我们可以访问原生事件对象
if (event) {
event.preventDefault()
}
alert(message)
}
}
})
</script>
事件修饰符
- 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
- 使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。 .stop .prevent .capture .self .once .passive
html
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
按键修饰符
- v-on 在监听键盘事件时添加按键修饰符
html
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<input v-on:keyup.page-down="onPageDown">
按键码
- keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持。
- 为了支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名
- 你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
v-on:keyup.f1
Vue.config.keyCodes.f1 = 112
html
<input v-on:keyup.13="submit">
<!-- .enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right -->
系统修饰键
- 可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。 .ctrl .alt .shift .meta
请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode:keyup.17。
html
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
.exact 修饰符
- .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
html
<!-- 即使 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
为什么在 HTML 中监听事件?
- Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。
- 无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。