2020年4月份抱着对新技术的好奇,学过一点vue,写了份Vue浅知.md,当时还是满脑子就业做运维,时隔5个月,已经在转行做前端的路上了,或许一切都是缘分吧。

[TOC]

Hello Vue ! 💝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>10-19 vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p> {{ msg }} </p>
</div>

<script>
new Vue({
el: '#app',
data: {
msg: 'hello vue'
}
});
</script>
</body>
</html>

引入vue:

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

推荐一个属于Vue的Chrome插件Vue.js devtools

devtools-vue


插值表达式和过滤器

  1. 插值: 通过 {{ message }} 的方式将JS代码中的变量放到html中渲染变量
  2. 通过插值表达式渲染的变量相当于v-text指令,变量中的html代码不会被渲染为样式
1
2
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
  1. 过滤器用于对插值表达式后的变量进行进一步的处理
  2. 定义过滤器的语法:Vue.filter(filterName,function(data,args))
  3. 使用过滤器的语法:{{ msg | filterName(args) | .... }}
  4. 下面演示定义一个全局的过滤器,demo会让所有的变量在后面加~~~+args
1
2
3
4
5
6
7
8
9
<!-- 定义一个过滤器 -->
<script>
Vue.filter('addWave',(data,args)=>{
return data + '~~~' + args;
});
</script>

<!-- 使用过滤器 -->
<p> {{ msg | addWave('!') }} </p> ===> hello vue~~~!

变量渲染 🏳‍🌈 v-once/text/html

  1. 一次性渲染变量:v-once
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
<!-- 结果是hello vue -->
<p v-once> {{ msg }} </p>
</div>


<script>
new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
// 这里涉及到生命周期钩子函数,本节最后一张有讲到,可以先去看看
mounted(){
this.msg = "123"
}
});
</script>
  1. 渲染变量为文本:v-text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<!-- <h3>hello vue</h3> -->
<p v-text="msg"> </p>
</div>


<script>
new Vue({
el: '#app',
data: {
msg: '<h3>hello vue</h3>'
},
});
</script>
  1. 渲染变量为html:v-html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<!-- hello vue -->
<p v-html="msg"> </p>
</div>


<script>
new Vue({
el: '#app',
data: {
msg: '<h3>hello vue</h3>'
},
});
</script>

😀 绝对不是在水字数

条件渲染 🏳‍🌈 v-if/show

v-ifv-elsev-else-if,当if后面的条件成立时,显示DOM元素

Syntax:isRender定义在vue实例的data中,使用v-if和v-show两个指令控制p标签里面的内容是否被渲染到页面上

1
2
3
<p v-if="isRender"> {{ msg }} </p>
||
<p v-show="isRender"> {{ msg }} </p>

v-ifv-show的区别:

  1. 实现原理的区别:v-show 渲染的元素始终会保留在DOM中,消失只是给元素添加了display:none的样式,而v-if是删除/创建元素
  2. v-show初始渲染开销大,v-if切换开销大

属性绑定 🏳‍🌈 v-bind

属性绑定可以动态的渲染样式,也可以给组件传递属性值,实现组件间通信,下面是v-bind的基本语法

1
v-bind:style <!--可以缩写为--> :style

v-bind使用场景:

  1. 单一属性绑定 - 绑定对象

    1
    2
    3
    4
    5
    6
    7
    8
    v-bind:class="{ 'active': isActive, 'text-danger': hasError }"

    data: {
    isActive: true,
    hasError: false
    }

    最后的结果就是class="active"
  2. 绑定对象内容定义在data里,不写在html模板 - 绑定对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div v-bind:class="classObject"></div>

    data: {
    classObject: {
    active: true,
    'text-danger': false
    }
    }
    绑定结果是:class="active"
  3. 使用计算属性进行绑定 - 绑定对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <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'
    }
    }
    }
  4. 绑定数组

    1
    2
    3
    4
    5
    6
    7
    8
    <div v-bind:class="[activeClass, errorClass]"></div>

    data: {
    activeClass: 'active',
    errorClass: 'text-danger'
    }

    渲染结果:<div class="active text-danger"></div>
  5. 三元表达式

    1
    <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
  6. 绑定内联样式 - 使用对象绑定

    1
    2
    3
    4
    5
    6
    7
    <div v-bind:style="styleObject"></div>
    data: {
    styleObject: {
    color: 'red',
    fontSize: '13px'
    }
    }
  7. 绑定内联样式 - 使用数组绑定

    1
    <div v-bind:style="[baseStyles, overridingStyles]"></div>
  8. 多重值,渲染数组中最后一个被浏览器支持的值

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

双向绑定 🏳‍🌈 v-model

v-model在表单 <input><textarea><select> 元素上创建双向数据绑定

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 property 并将 change 作为事件。

下面这个例子是用户在文本框内输入内容,下方会有一个p标签实时呈现用户输入内容

1
2
3
4
<div id="app">
<input type="text" v-model="msg">
<p> {{ msg }} </p>
</div>

事件绑定 🏳‍🌈 v-on

下面内容包括v-on的基础语法、事件修饰符、键盘修饰符、鼠标修饰符相关内容

将函数绑定到用户行为或者浏览器行为,当事件触发时,执行相应的动作,下面是v-on的语法,v-on可以简写为@

1
2
3
<div id="app">
<button @click="showMsg"> click me </button>
</div>
1
2
3
4
5
6
7
8
new Vue({
el: '#app',
methods: {
showMsg: function(){
console.log("be clicked.")
}
}
})

事件修饰符:阻止事件不再传播,.stop/.prevent/.capture/.self/.once/.passive

  • .stop :阻止单击事件继续传播
  • .prevent:提交事件不再重载页面
  • .capture
  • .self
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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
3
4
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

<input v-on:keyup.page-down="onPageDown">

键盘修饰符:.enter/.tab/.delete(捕获“删除”和“退格”键)/.esc/.space/.up/.down/.left/.right/.ctrl/.alt/.shift/.meta/.exact

extract:允许你控制由精确的系统修饰符组合触发的事件,类似于当Ctrl和Shift同时按下去,会触发哪个修饰符

鼠标修饰符:.left/.right/.middle

语法:

1
@keyup.enter="do"

对于Vue没有定义的键盘修饰符,Vue允许用户自定义,下面介绍自定义键盘修饰符

用法:https://cn.vuejs.org/v2/api/#keyCodes

键码值:https://www.bejson.com/othertools/keycodes/

1
Vue.config.keyCodes.f1 = 112

循环变量 🏳‍🌈 v-for

v-for 渲染数组

  1. 可以访问父作用域里的所有属性
  2. 可以使用of替代in作为分隔符,这里两者都是取的每一项
  3. 支持遍历对象,默认value in object得到的value是值,而非属性
  4. 遍历对象时,支持第二参数即:(value,name) in array,其中name是属性,value是值
  5. 遍历对象时,支持第三参数即:(value,name,index) in array,其中index是索引,从0开始
  6. 渲染的数据可以实计算属性的返回值,也可以是方法的返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div id="app">
<ul>
<li
v-for="item in items"
v-bind:key="item.id"
>
{{ item.msg }}
</li>
</ul>
</div>


<script>
new Vue({
el: '#app',
data: {
items: [
{id:1,msg:"Lorem ipsum dolor sit amet consectetur a"},
{id:2,msg:"dipisicing elit. Blanditiis a"},
{id:3,msg:"ut excepturi praesentium id aspernatur "},
{id:4,msg:"voluptas optio iste provident velit cupiditate"}
]
},
});
</script>

自定义指令 🏳‍🌈 v-focus

https://cn.vuejs.org/v2/guide/custom-directive.html

对于没有的vue指令,vue允许用户自定义vue指令,自定义指令又分为全局指令和私有指令,下面介绍全局自定义指令的语法:

Vue.directive('directName'{ el-liftcycle })

1
<input type="text" v-focus>
1
2
3
4
5
6
Vue.directive('focus',{
// 当元素被插入到DOM中时,聚焦
inserted: el=>{
el.focus()
}
})

这里面有几点需要注意:

  1. 命名的时候不需要加v-,框架会自动帮我们加,调用的时候用v-directName即可
  2. 自定义指令的第二个参数是生命周期对象,其值有:bind/inserted/update/componentUpdated/unbind,分别表示在不同的时间段执行相应操作
  3. 每个生命周期钩子函数都可以传递三个参数:el/binding/vnode,下面解释一下这三个参数
    • el: 指令绑定的元素,即DOM对象
    • binding:一个包含了绑定指令参数的对象,其中比价重要的有:
      • name:指令名称(不包含v-前缀)
      • value:指令绑定的值
      • arg: 指令接受的参数
    • vnode:Vue编译产生的虚拟节点

举个例子,就拿上面的案例扩容一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<!-- 这里的red先用双引号,后用单引号,表示字符串;如果只用双引号,则表示变量,值为undefined-->
<input type="text" v-focus:apple="'red'">
</div>
-------
Vue.directive('focus',{
// binding.value = red
// binding.arg = apple
inserted: (el,binding,vnode)=>{
let statement = `this is a ${binding.value} ${binding.arg}`;
el.value = statement;
el.focus()
}
})

效果展示

操作DOM 🏳‍🌈 $ref

Vue不建议我们通过getElementById()的方式直接操作DOM,给我们提供了$ref的方法简洁获取DOM元素,下面给出例子和语法:

1
2
3
4
5
// 在html中,通过ref绑定元素
<p ref='litp'> hello vue</p>

// 在VUE实例中,通过this.$refs.elName 获取绑定元素的DOM对象
this.$refs.litp.innerHTML = "HELLO Paragraph"

Vue实例 🏳‍🌈 Options

options是传递给vue实例的一个对象,主要是用来操作Vue实例内的数据,需要注意的是,这些内部的数据都是当前vue实例私有的,不能被外部访问,其基本格式为(也是我我们下面要写的内容):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
new Vue({
el: '#app', // 实例挂载
data: {}, // 数据内容
methods: {}, // 函数方法
filters: {}, // 过滤函数
components: {}, // 私有组件(在vue-组件中再讲)
computed: {}, // 计算属性
watch: {}, // 监听器
directives: {}, // 私有指令

// 生命周期,钩子函数
beforeCreate(){},
created(){},
beforeMount(){},
mounted(){},
beforeUpdate(){},
updated(){},
...
})

methods 🚀 函数方法

函数方法定义了实现某一功能的代码集合,这里主要讲一下实例中,methods方法的定义和使用

  1. 定义:在vue实例下的methods对象中定义方法,格式为funcName: function(){}
1
2
3
4
5
6
7
8
9
10
11
12
new Vue({
el: '#app',
data: {
msgf: 'hello',
msgs: 'vue'
},
methods: {
mergeMsg: function(){
return this.msgf + this.msgs;
}
}
})
  1. 调用(一般情况下,方法会被v-on事件调用,v-on可以调用鼠标、键盘等多种事件绑定,见上文)
1
2
3
<div id="app">
<p> {{ mergeMsg() }} </p>
</div>

computed 🚀 计算属性

计算属性可以更优雅对变量进行处理和调用,这里主要讲一下实例中计算属性的定义和使用,以及计算属性和函数方法的区别

  1. 定义:在vue实例下的computed对象中定义,格式为computedName: function(){}
1
2
3
4
5
6
7
8
9
10
11
12
new Vue({
el: '#app',
data: {
msgf: 'hello',
msgs: 'vue'
},
computed: {
mergeMsg: function(){
return this.msgf + this.msgs;
}
}
})
  1. 调用
1
2
3
<div id="app">
<p> {{ mergeMsg }} </p>
</div>

计算属性的本质就是一个对象的get方法,它也可以设置set方法,但没必要。

1
2
3
4
5
6
7
computed: {
mergeMsg: {
get: function(){
return this.msgs + this.msgf
}
}
}

计算属性和普通方法的区别:

  1. 普通方法调用的时候需要加上() ,而计算属性调用只需要写变量名
  2. 计算属性本质上是一个包含get方法的对象,只是简化成函数的形式而已,而普通方法本身就是函数
  3. 计算属性会有缓存,如果计算涉及到的变量不改变,则默认返回缓存中的值,下面通过一个例子展示一下:
1
2
3
4
5
<div id="app">
<p> {{ mergeMsg }} </p>
<p> {{ mergeMsg }} </p>
<p> {{ mergeMsg }} </p>
</div>
1
2
3
4
5
6
computed: {
mergeMsg: function () {
console.log("only be called once")
return this.msgs + this.msgf
}
}

页面输出三次vuehello ,但console只输出一次only be called once

watch 🚀 监听器

定义:在vue实例下的watch对象中定义,格式为variable: function(){},variable是需要监听的变量,变量一旦改变,就执行后面的函数,下面是监听器的基本语法,分别为html代码和vue代码

1
2
3
<div id="app">
<input type="text" v-model='msg'>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
new Vue({
el: '#app',
data: {
msg: 'hello'
},
watch: {
// msg的值改变,下面这个函数就会运行
msg: function(){
console.log("msg has been changed.")
}
}
})

watch监视路由变化

1
2
3
this.$route.path : function(newVal,oldVal){
console.log(newVal,oldVal); // ==> newVal: register oldVal: login
}

LifeCycle 🚀 钩子函数

Vue实例的生命周期流程图

  • beforeCreate() 这个函数执行时,vue里面的数据还没有被初始化,data、methods等不存在,不能被调用
  • created() Vue实例内容初始化,可以调用里面的data和methods
  • beforeMount() 模板已经编译完放在内存中,但是尚未挂载到DOM;此时插值表达式没有被渲染,还是 的形式
  • mounted() 实例已经完全创建并挂载到页面,如果要操作DOM节点,需要在mounted或之后操作;之后组件脱离了创建阶段,到达运行阶段
  • beforeUpdate() 数据被更新了,但是页面没有被更新;Vue实例中的数据改变了,但是页面中的数据还没改变,数据未同步
  • updated() 虚拟DOM树重新渲染,页面内容和数据内容保持一致,页面被更新

例子和语法

1
2
3
<div id="app">
<p> hello vue</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
new Vue({
el: '#app',
data: {
msg: 'x'
},
// 当vue实例挂载到DOM节点时,修改p标签的内容,最好用$refs得到DOM元素,这里就用children了
mounted(){
this.$el.children[0].innerHTML = "hello HXW"
console.log(this);
}
})