言成言成啊 | Kit Chen's Blog

Vue基础

发布于2022-04-08 00:24:09,更新于2022-04-30 11:00:34,标签:web  转载随意,文章会持续修订,请注明来源地址:https://meethigher.top/blog

文档

  1. 介绍 — Vue.js
  2. 风格指南 — Vue.js
  3. hexo中对占位符的解析 | TonyStudio

Vue是一套用于构建用户界面的渐进式JavaScript框架。

何为渐进式?

Vue可以创建自底向上逐层的应用,从简单应用到复杂应用。

如果是简单应用,只需要一个轻量的核心库。

如果是复杂应用,可以引入各式各样的vue插件。

Vue特点

  1. 采用组件化模式,可复用、好维护。一个.vue就可以作为一个组件,其中包含html、css、js
  2. 声明式编码,无需直接操作dom。像直接操作dom的就叫做命令式编码,有点像面向对象与面向过程的区别,具体区别可以看图。
  3. 使用虚拟dom和diff算法,尽量复用dom。也就是数据发生变化,只进行增量更新。

一、上手

像vue下面这样的语法,就叫做模板语法,模板语法又分很多类。

1
2
3
<div id="test">
Hello {{message}}
</div>

1.1 占位语法

遇到了点hexo的冲突问题,hexo中的占位符敲好也是{{}}或者{%%}

所以如果想要展示原内容的话,语法需要像下面这样使用

{% raw %}文章内容{% endraw %}
{{content}}表示占位符,content内容支持js表达式。

占位语法一般用于标签体内容

一般真实开发也只会有一个Vue示例,并且是配合组件一起用的。

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
26
27
28
29
30
31
32
33
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">
Hello {{message.toUpperCase()}},My name is {{name}},now timestamp is {{Date.now()}}, I will calculate 1+1 for you, the result is
{{1+1}},
</div>
<div id="test">
Hello {{message}}
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.config.productionTip = false;
const app = new Vue({
el: '#root',
data: {
message: 'Vue',
name: "ccc"
}
});


</script>
</body>
</html>

1.2 指令语法

vue有很多指令,格式都是v-xxx

v-bind这种就是指令语法,v-bind可以简写为:

指令语法用于标签,作用范围包含并大于占位语法

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
26
27
28
29
30
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<a v-bind:href="link">{{blogName}}</a>
<a :href="link">{{blogName}}</a>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.config.productionTip = false;
const app = new Vue({
el: '#app',
data: {
blogName: '博客',
link:"https://meethigher.top"
}
});


</script>
</body>
</html>

1.3 数据绑定

v-bind是单向数据绑定,也就是绑定的值,如果通过页面进行了修改,原本的值不会变化。

v-model支持双向数据绑定,如果页面的值发生变化,绑定的值也会变化。

v-model只能用在输入类元素,也就是内容可编辑的元素。

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
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">
单向数据绑定:<input type="text" v-bind:value="name">
双向数据绑定:<input type="text" v-model:value="name">
</div>
<script src="js/vue.js"></script>
<script>
new Vue({
el:'#root',
data: {
name:'test'
}
})
</script>
</body>
</html>

1.4 el与data的两种写法

el两种写法

  1. new对象时配置el属性
  2. 通过创建的对象使用$mount指定el的值

data两种写法

  1. 对象式
  2. 函数式

使用组件时,data必须使用函数式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
/*第一种写法*/
// new Vue({
// el:'#root',
// data: {
// name:'test'
// }
// });
/*第二种写法,el使用mount,data使用函数*/
const app = new Vue({
//data: function ()可以简写为data()
data: function () {
//this是vue对象
console.log(this);
return {
name: "test"
}
}
});
app.$mount("#root");
</script>

1.5 vue中的mvvm模型

M:model模型,对应data中数据

V:view视图,对应vue模板

VM:viewModel视图模板,对应vue对象

对使用者,跟后端的MVC没啥区别,只不过控制器换成了视图模板罢了。

视图模板本身和控制器作用也是一样的,调用数据model,将数据model返回给view视图使用。

1.6 数据代理

通过Object.defineProperty添加属性值,该属性值的key在遍历时,是不会被遍历到的

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
let person={
name:"test",
age:18
};
/*这样定义的不会参与遍历*/
Object.defineProperty(person,"sex",{
value: "男"
});
console.log(person);
//遍历key
console.log(Object.keys(person))
</script>

当然了,我们也可以给他们配置属性,允许该操作。

1
2
3
4
5
6
7
8
9
10
/*允许被遍历*/
Object.defineProperty(person,"sex",{
value: "男",
//控制属性可以被遍历,默认false
enumerable:true,
//控制属性可以被修改,默认false
writable:true,
//控制属性可以被删除,默认false。通过控制台delete person.sex测试
configurable:true
});

如果,我们想要动态修改对象中的值,可以这么玩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
let sex="男";
let person={
name:"test",
age:18
};

//让值为动态的
Object.defineProperty(person,"sex",{
//读取值
get() {
console.log("读取sex");
return sex;
},
//修改值
set(value) {
console.log("修改sex");
sex=value;
}
});
console.log(person);
</script>

1.7 事件与事件修饰符

注意事项

  1. 使用v-on:xxx或者@xxx绑定事件,其中xxx是事件名,比如click
  2. 事件如果放在data中,会自动生成getter与setter,建议放在methods中
  3. methods中如果用箭头函数,this就表示window。不用箭头函数,this表示vue对象
  4. @click=”function”与@click=”function($event)”一样,前者是后者省略写法。
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
26
27
28
29
<div id="root">
<button v-on:click="showInfo
<button @click="showInfo">@简
<button @click="showInfoWith
</div>
<script>
const app=new Vue({
el:"#root",
data:{
name:"meethigher",
address:"china"
},
methods: {
// showInfo() {
// alert("test"
// }
showInfo(a,b,c,d) {
//只有第一个参数,a有值,也
console.log(a,b
//此时thisvue对象,
console.log(thi
},
showInfoWithParam(p
console.log(eve
alert(param);
}
}
});
</script>

对于事件修饰符,拿阻止默认事件来说,我们从js的语法写vue可以这样

1
2
3
4
5
showInfo(e) {
//阻止默认行为,比如a标签点击跳转,阻止后就不用跳转了
e.preventDefault();
alert("test");
}

但是vue给提供了更方便的写法

1
2
3
<div id="root">
<a href="https://meethigher.top" @click.prevent="showInfo">test</a>
</div>

像这种还有很多,vue中常用的事件修饰符

  1. prevent:阻止默认事件,常用
  2. stop:阻止事件冒泡,常用
  3. once:事件只触发一次,常用
  4. capture:使用事件的捕获模式
  5. self:只有event.target是当前操作的元素才会触发
  6. passive:事件的默认行为立即执行,不需要等待事件回调完成

修饰符可以连写

.prevent.stop,先阻止默认事件,再阻止冒泡

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<style>
.test {
margin: 10px auto;
background-color: #42b983;
}
.aaa {
height:250px;
overflow: auto;
}
.aaa>li {
margin: 10px auto;
height: 200px;
background-color: green;
}
</style>

<div id="root">
<!--阻止默认事件,不阻止会进行跳转-->
<a href="https://meethigher.top" @click.prevent="showInfo">test</a>
<!--阻止冒泡,不阻止会执行方法两次-->
<div class="test" @click="showInfo">
<button @click.stop="showInfo">测试冒泡</button>
</div>
<!--设置事件只触发一次-->
<button @click.once="showInfo">事件只触发一次</button>
<!--使用事件的捕获模式,就是在捕获阶段就开始执行。
js点击事件的触发,分两个阶段,
一个是捕获阶段,从dom树最外层找到最内层,
然后才是冒泡阶段,冒泡阶段是从内向外。
点击div2正常log顺序是2,1,如果对div1进行捕获,输出就成了1,2
-->
<div class="test" @click.capture="showMsg('div1')">
div1
<div class="test" @click="showMsg('div2')">
div2
</div>
</div>
<!--只有event.target是当前操作的元素才会触发-->
<div class="test" @click.self="showTarget">
<button @click="showTarget">测试只有当前元素才能触发</button>
</div>
<!--事件的默认行为立即执行,无须等待事件回调执行完毕
滚动事件有scroll,还有wheel
scroll指滚动条移动,先移动再执行事件
wheel指鼠标滚轮移动,执行完事件再移动
-->
<ul class="aaa" @wheel.passive="calculate">
<li>向晚</li>
<li>贝拉</li>
<li>珈乐</li>
<li>嘉然</li>
<li>乃琳</li>
</ul>
</div>

<script>
const app=new Vue({
el:"#root",
data:{
name:"meethigher",
address:"china"
},
methods: {
showInfo(e) {
// e.preventDefault();//阻止默认事件
//e.stopPropagation();//阻止冒泡
alert("test");
},
showMsg(param) {
console.log(param);
},
showTarget(e) {
console.log(e.target);
},
calculate() {
for (let i=0;i<100000;i++) {
console.log("a");
}
console.log("算完了");
}
}
});
</script>

1.8 键盘事件

先看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="root">
<input type="text" placeholder="按下回车提示输入" @keydown="showInfo">
</div>

<script>
new Vue({
el:"#root",
methods: {
showInfo(e) {
if(e.keyCode!==13) return;
console.log(e.target.value);
}
}
})
</script>

一般操作是上面这样进行的,但是在Vue中,提供了常用的按键别名

  1. 回车:enter
  2. 删除:delete
  3. 退出:esc
  4. 空格:space
  5. 换行:tab,必须与keydown使用
  6. 上:up
  7. 下:down
  8. 左:left
  9. 右:right
  10. ctrl
  11. alt
  12. shift
  13. meta:对应windows的win键
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="root">
<input type="text" placeholder="按下ctrl+enter提示输入" @keydown.ctrl.enter="showMsg">
<input type="text" placeholder="按下ctrl+enter提示输入" @keydown.ctrl.e="showMsg">
</div>

<script>
// 自定义全局按键修饰符
Vue.config.keyCodes.e = 69;
new Vue({
el:"#root",
methods: {
showInfo(e) {
console.log(e.target.value);
}
}
})
</script>

1.9 计算属性

需求

两个输入框,一个姓,一个名,下面文本框动态展示姓名。

占位符实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="root">
姓:<input type="text" v-model="xing"><br>
名:<input type="text" v-model="ming"><br>
全名:{{xing.slice(0,3)}}{{ming}}
全名:{{xing.slice(0,3)}}{{ming}}
</div>
<script src="js/vue.js"></script>
<script>
new Vue({
el:"#root",
data: {
xing: '',
ming:''
}
})
</script>

修改一次,调用两次。

方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div id="root">
姓:<input type="text" v-model="xing"><br>
名:<input type="text" v-model="ming"><br>
全名:{{getFullName()}}
全名:{{getFullName()}}
</div>
<script src="js/vue.js"></script>
<script>
new Vue({
el:"#root",
data: {
xing: '',
ming:''
},
methods: {
getFullName() {
console.log("方法被调用");
return this.xing.slice(0,3)+this.ming;
}
}
})
</script>

修改一次,方法调用两次。

计算属性实现

很明显,不管是占位符或是方法,都是在只要数据发生变化后,都要重新读取一下,效率不高。

Vue提供了计算属性,为了解决这个问题,计算属性里面用到了缓存,将数据缓存了起来,便于后续的复用。

何为属性,vue对象中的data里面的可以都是属性(属性名)。

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
26
27
28
29
30
<div id="root">
姓:<input type="text" v-model="xing"><br>
名:<input type="text" v-model="ming"><br>
全名:{{getFullName}}<br>
全名:{{getFullName}}
</div>
<script src="js/vue.js"></script>
<script>
const app=new Vue({
el:"#root",
data: {
xing: '',
ming:''
},
computed: {
getFullName: {
//有人读取fullName时,get就会被调用,并将其返回值作为getFullName的值
get(){
console.log("被调用了");
return this.xing+this.ming;
},
/*控制台通过app.getFullName=xxx即可执行*/
set(value) {
console.log("set被调用");
this.xing=value;
}
}
}
})
</script>

修改一次,只调用一次。

计算方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
const app=new Vue({
el:"#root",
data: {
xing: '',
ming:''
},
computed: {
getFullName() {
console.log("被调用了");
return this.xing+this.ming;
}
}
})
</script>

1.10 监视属性

需求

实现一个切换天气按钮,获取当前天气和上一次天气。

常规实现

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="root">
<h2>今天天气很{{weather}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: "#root",
data: {
isHot: true
},
methods: {
changeWeather() {
this.isHot = !this.isHot;
}
},
computed: {
weather() {
return this.isHot ? "炎热" : "凉爽";
}
}
});
</script>

监视属性实现

监视属性的两种实现

  • 实例化Vue对象时,初始化配置watch
  • 通过已有的Vue对象,obj.$watch监视
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<div id="root">
<h2>今天天气很{{weather}}</h2>
<button @click="changeWeather">切换天气</button>
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: "#root",
data: {
isHot: true
},
methods: {
changeWeather() {
this.isHot = !this.isHot;
}
},
computed: {
weather() {
return this.isHot ? "炎热" : "凉爽";
}
},
// 实例化Vue对象时,初始化配置watch
// watch: {
// isHot: {
// //初始化时,令handler调用一次
// immediate:false,
// //当isHot这个值发生变化时,自动true
// handler(newValue,oldValue) {
// console.log("isHot被修改了",newValue,oldValue);
// }
// },
// weather: {
// immediate:true,
// handler(newValue, oldValue) {
// console.log("监测weather方法",newValue,oldValue);
// }
// }
// }
});

// 通过已有的Vue对象,obj.$watch监视
app.$watch("weather",{
immediate:true,
handler(newValue, oldValue) {
console.log("监测weather方法",newValue,oldValue);
}
})
</script>

vue默认不监视多层级数据的变化,如果想要监视多层级监视,就要配置deep。

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="root">
<button @click="number.a++">a++</button>
</div>

<script>
const app = new Vue({
el: "#root",
data: {
isHot: true,
number: {
a:1,
b:2
}
},
watch: {
number: {
deep: true,
/*多层次数据监视,vue默认不监视下面层次数据的变化*/
handler() {
console.log("number发生变化");
}
}
}
});
</script>

1.11 绑定样式

绑定class

vue绑定样式需要使用:class,参数内容支持字符串、数组、对象(key的值需要是boolean类型)。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<div id="root">
<div id="weather" class="basic" :class="[weatherClass,weatherValid]" >今天的天气:{{weather}}</div>
<button @click="changeWeather">查询当前天气</button>
<button @click="addFont">添加字体样式</button>
</div>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: "#root",
data: {
// weatherClass: ["basic","sunny"],//多样式时的写法
weatherClass: "sunny",
weather: "晴天",
/*为false时,表示:class的引用不生效,true表示生效*/
weatherValid: {
isValid: false
}
},
methods: {
changeWeather() {
const arr=["sunny","cloudy","rain"];
const arrDesc=["晴天","多云","雨天"];
const index=Math.floor(Math.random()*3);
this.weatherClass=arr[index];
this.weather=arrDesc[index];
},
addFont() {
let weatherClass = this.weatherClass;
if(weatherClass instanceof Array) {
console.log("是数组,追加");
this.weatherClass.push("font");
}else {
console.log("不是数组,拼接");
this.weatherClass=this.weatherClass+" font";
}
}
}
})
</script>
发布:2022-04-08 00:24:09
修改:2022-04-30 11:00:34
链接:https://meethigher.top/blog/2022/vue-base/
标签:web 
付款码 打赏 分享
shift+ctrl+1可控制目录显示