Vue-基础

— 点点开发技能树 —
— Vue环境 及 语法 —

Vue

Vue是一种前端JS框架,这里根据《Vue.js实战》 以及 官网教程 记录了下学习笔记,方便以后回忆。

Vue开发环境

通常有两种方式使用Vue——作为js包进入,直接使用;当做使用npm安装框架,然后模块开发。

网页快速开发

  • 引入vue.js
    • 开发版本(有错误调试信息)vue.js<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    • 生产版本vue.min.js<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
  • 编写vue

框架开发 Vue-cli

npm i vue-cli -g:全局安装vue-cli
vue init webpack:使用webpack作为模板(simple是功能简化)

npm run dev:开发环境下加载项目,包括以下步骤

  • 加载环境变量:加载config下index.js和dev.env.js
  • 合并webpack配置:合并webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.con.js
  • 配置热加载:修改的代码可以实时应用
  • 配置代理服务器:为增加模拟服务端做准备
  • 配置静态资源:配置静态文件到static虚目录中
  • 加载开发服务器:启动一个Express的WEB服务器

npm run build:编译生产环境

具体利用webpack作为模板,Vue框架开发,在另一篇中具体说明


选项

选项相当于Vue的小组件,构成Vue的功能,对象,数据,生命周期,通讯,监听等等。

Vue常用选项

Vue结构和常用选项如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var app = new Vue({
el: '', //挂载DOM对象
data: { //数据

},
methods: { //事件处理器

},
computed: { //计算属性

}
components: { //注册局部组件

}
filters: { //过滤器

}
})

所有的选项都不要使用() =>的形式来定义函数,这是因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同。(不懂,但是都是用function()吧)

DOM

el 挂载点

  提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。

template

  通常在模块中使用。提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。

  在模块中说明

render

  字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。

  使用方法很高端,没用过,不详细说明

数据

Vue中的数据形式分为:数据data,计算属性computed。另外说明数据输出到html的方式

data 数据

1
2
3
4
5
6
7
8
9
10
11
12
//new Vue 中可以返回对象
data :{ //数据
firstName : 'jack',
lastName : 'Green'
},
//Vue组件中 只可以返回函数
data :function() {
return {
firstName : 'jack',
lastName : 'Green'
}
}

computed 计算属性

  计算属性 就是多个数据经过各种复杂的计算,最终返回一个结果
  每一个计算属性都包含一个getter和一个setter,默认是只有getter

  • 当用到的数据有一个发生变化,计算属性的getter就会重新执行
  • 当计算属性的结果更新是,setter就会执行

姓名的姓氏和名字互相组合替换功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
data :{
firstName : 'jack',
lastName : 'Green'
},
computed:{ //默认就是getter的情况
fullName : function(){
return this.firstName + ' ' + this.lastName;
}
}
computed:{ //两者都有的情况
fullName : {
get: function(){
return this.firstName + ' ' + this.lastName;
},
set: function(){
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
}
}

显示数据

Vue会根据双括号来动态替换数据

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<h2>{{filename}}</h2>
</div>

<javascript>
var app = new Vue({
data: {
filename: 'file'
}
})
</javascript>

事件/监听

事件 methods

methods自定义触发函数

1
2
3
4
5
6
7
8
9
10
var vm = new Vue({
data: { a: 1 },
methods: {
plus: function () {
this.a++
}
}
})
vm.plus()
vm.a // 2

结合v-on指令可以构成事件。

监听 watch

  watch选项用来监听某个prop或data的改变,当他们发生变化时,就会触发watch配置的函数。

1
2
3
4
5
6
watch:{
//监听Value变量
Value: function (val){
this.currentValue = val; //使用父组件的v-model改变值
}
}

生命周期钩子

生命周期钩子,就是在页面渲染到不同的阶段,执行自定义的操作。列出所有,选一个常用的mounted说明:

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • activated
  • deactivated
  • beforeDestroy
  • destroyed
  • errorCaptured

生命周期图例

以下说明各个生命周期钩子的位置,以及已经执行了什么。
生命周期图例

mounted

  当挂载完成后,调用该钩子.注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted

1
2
3
4
5
6
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}

过滤器 filters

  过滤器可以用在两个地方:双花括号插值v-bind 表达式
  过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:

1
2
3
4
5
6
7
8
9
10
<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

<!-- 过滤器可以串联 -->
{{ message | filterA | filterB }}
<!-- 过滤器可以接受参数 参数1:message 参数二:arg1 参数三:arg2 -->
{{ message | filterA('arg1', arg2) }}

自定义过滤器

  在一个组件的选项中定义本地的过滤器:

1
2
3
4
5
6
7
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}

  或全局定义过滤器

1
2
3
4
5
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})

组件 components

  使用components可以用Vue.component定义一个新的组件,也可以在父组件内定义(如同其他选项一样)。
  具体在组件篇中说明


指令

Vue指令有很多,说明常用指令

v-cloak

  当在简单的项目中,js还没有加载完时,页面会显示一些未渲染完的东西比如{{name}},在加载完后会闪动页面刷新显示。而在工程化项目里,因为HTML结构只有一个空的div元素,所以不会有闪动情况。
  v-cloak就是用于vue.js还未加载完时,隐藏vue的html部分。

  • 不需要表达式
  • 通常与css一起使用。

html页面

1
2
<div id='app' v-cloak>
</div>

css页面

1
2
3
[v-cloak] {
diaplay: none
}

v-once

  v-once:定义他的元素或组件只渲染一次,包括元素或者组件的所有子节点。首次渲染后,不再跟随数据的变化重新渲染,将被视为静态内容。

v-bind 修改属性

v-bind:可以动态修改标签的属性
下面说细节的使用方式

字符串语法

字符串语法可以动态调用变量

1
2
3
4
5
6
//直接使用,用data中的url动态更新href属性
<a v-bind:href="url">链接</a>
...
data: {
url: "http://www.abc.com"
}

字符串语法可以调用methods函数,动态调整参数

1
2
3
4
5
6
7
8
9
10
11
//
<a v-bind:href="geturl(this.param)">链接</a>
...
data:{
param: "123"
}
methods: {
geturl : function(){
return "http://"+param;
}
}

对象语法

1
2
3
4
5
6
7
//使用语法糖(省略写法),根据data中的布尔型isActive,来判断是否显示字符串active
<div :class="{ 'active': isActive , 'error': isError }"> </div>
...
data: {
isActive: true,
isError: false
}

数组语法

1
2
3
4
5
6
7
//使用语法糖,根据data中的对象值,来填入class
<div :class="[ activeCls , errorCls ]"></div>
...
data: {
activeCls : 'actice',
errorCls : 'error'
}

数组语法 + 对象语法

1
2
3
4
5
6
7
//使用语法糖,isActive为正时,显示active
<div :class="[ { 'active': isActive }, errorCls ]"></div>
...
data: {
isActive: true,
errorCls : 'error'
}

  不过可用变量也不一定是data下的数据,在computed选项,或者在语句中产生的变量也可以使用

v-if  v-else-if  v-else

  条件渲染指令
  v-else-if要紧跟v-if,v-else要紧跟v-else-ifv-if。表达式的值为真时,当前元素/组件及所有子节点将被渲染,为假时被移除。

1
2
3
4
5
6
7
8
9
10
11
12
<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>

template 多元素渲染

  如果以此判断的是多个元素,可以在Vue.js内置的<template>元素上使用条件指令,最终渲染的结果不会包括该元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<template v-if="status === 1">
<p>test 1</p>
<p>test 2</p>
</template>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
status: 1
}
})
</script>

v-show

  根据表达式之真假值,切换元素的displayCSS属性。

1
<h1 v-show="status === 1">Hello!</h1>

v-show 不支持 <template> 元素,也不支持 v-else
v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

v-for

  数组、对象遍历显示时会用到v-for,他的表达式需结合in,利用item in items的形式来使用。items是源数据数组并且item是数组元素迭代的别名。

数组

1
2
3
4
5
6
7
8
<!-- 数组,值 -->
<div v-for="item in items">
{{ item.text }}
</div>
<!-- 数组,值+索引 -->
<div v-for="(item,index) in items">
{{ item.text }}
</div>

对象

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 对象,值 -->
<div v-for="value in object">
{{ value }}
</div>
<!-- 对象,值+键名 -->
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
<!-- 对象,值+键名+索引 -->
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>

template 多元素渲染

1
2
3
4
5
6
<ul>
<template v-for="book in books">
<li>书名:{{book.name}}</li>
<li>作者:{{book.name}}</li>
</template>
</ul>

数组更新

改变数组会触发视图更新

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

返回新数组,不会触发视图更新

  • filter()
  • concat()
  • slice()

不会触发视图更新的:

  • 通过索引直接设置项 app.books[3]={}
  • 修改数组长度 app.books.length=1

第一个问题可以使用Vue.ser$set来实现

1
2
3
4
5
6
7
8
9
Vue.set(app.books, 3, {
name: '《CSS揭秘》',
author: 'Lea Verou'
});
//webpack中使用组件化,默认是没有导入Vue的,使用$set
this.$set(app.books, 3,{
name: '《CSS揭秘》',
author: 'Lea Verou'
});

第一个问题,第二个问题都可以使用splice来解决

1
2
3
4
5
6
app.books.splice(3,1,{
name: '《CSS揭秘》',
author: 'Lea Verou'
});
//修改数组长度
app.books.splice(1);

v-on 事件监听器

1
2
3
4
5
6
7
8
9
10
//点击触发事件,执行js
<button v-on:click="handleClose">点击隐藏</button>
//语法糖写法
<button @click="handleClose">点击隐藏</button>
...
methods: {
handleClose: function() {

}
}

原生事件列表:

  • click
  • change

特殊参数$event:用于访问原生DOM事件,比如调用 event.stopPropagation()

事件修饰符

  在事件处理程序中调用event.preventDefault()event.stopPropagation()是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

  • stop:调用 event.stopPropagation()
  • .prevent:调用 event.preventDefault()
  • .capture:添加事件侦听器时使用 capture 模式
  • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调
  • .once:只触发一次回调
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- 阻止单击事件继续传播 -->
    <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>

按键修饰符

1
2
@keyup.13="submit" //在keyCode是13时 调用vm.submit
@click.ctrl="submit" //组合ctrl+点击 调用

v-model 双向绑定

  你可以用 v-model 指令在表单 <input><textarea> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

v-model 会忽略所有表单元素的 valuecheckedselected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。(需要自己写吧)

由于每个控件都可以使用v-model绑定到data数据:
控件分配:

  • 文本 <input>
  • 多行文本 <textarea>
  • 复选框 <input type="checkbox">
  • 单选按钮 <input type="radio">
  • 选择框 <select>

多个复选框,绑定到同一个数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id='example-3'>
<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>
</div>
<script>
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
</script>

其他请查看 官网

修饰符

  • .lazy:默认是在input时间中同步输入框的内容,.lazy会转变为在change事件中的同步。v-model.lazy
  • .number:可以讲输入转换为Number类型,否则即使输入的是数字,他的类型其实是字符串。v-model.number
  • .trim:可以自动过滤输入的首尾空格。v-model.trim

Vue特殊特性

属性 key

  Vue在渲染元素时,处于效率考虑,会尽可能地复用已有的元素而非重新渲染,比如下面的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<template v-if="type === 'name'">
<label>用户名:</label>
<input placeholder="输入用户名">
</template>
<template v-else>
<label>邮箱:</label>
<input placeholder="输入邮箱">
</template>
<button @click="handleToggleClick">切换输入类型</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
type: 'name'
},
methods: {
handleToggleClick: function() {
this.type = this.type === 'name' ? 'mail' : 'name';
}
}
})

  上面的程序点击切换按钮虽然DOM变了,但是之前在输入框键入的内容没有改变,只是替换了placeholder的内容,说明<input>元素被复用了。

  Vue.js提供的key属性,它可以让你自己决定是否要复用元素。
  有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

1
2
<input placeholder="输入用户名" key="name-input">
<input placeholder="输入邮箱" key="mail-input">

  如此可以使input元素各自有key