声明式渲染
初识 Vue 代码结构
app.vue
是工程的根组件,所以我们可以将学习的代码先写在app.vue
中。
如下图所示,我们注释了基础代码,并添加了 js 代码的书写位置:
下面我将代码贴出,来详细解释一下:
// template即模版的意思,每一个vue文件里必须要有一个,在这里写HTML代码
<template>
<div id="app"></div>
</template>
// 在这里写js逻辑相关的代码
<script>
export default {
name: "app"
};
</script>
// 这里写样式代码
<style></style>
通过对上述代码的阅读可以得出一个结论,每一个 Vue 文件由三部分组成,template
、script
、style
,它们分别对应 HTML
、JavaScript
、CSS
。
另外需要注意的一点是,在 template
里面只允许有一个块状元素,通常情况下在 template
里面写的都是 div
。
像下面这几种的写法是错误的:
- 错误示范 1
<template>
<div></div>
<div></div>
</template>
- 错误示范 2
<template>
<div></div>
<ul>
>
</ul>
</template>
- 错误示范 3
<template>
<div></div>
<span></span>
</template>
总之就是一句话template
标签内只能有一个块标签,其他所有的标签都在这个块标签内
声明式渲染
在学习JavaScript
的时候,我们使用的是模板字符串来将数据渲染在页面中的,那时候我们用的一个符号是${}
,具体代码如下:
let element = `<div>${data.name}</div>`;
那时候你一定问过这样一个问题,前端怎么这么复杂?
学习了 Vue 后,就再也不用那么复杂了,只需要使用差值表达式即可解决之前的所有烦恼。差值表达式很简单,就是一个两层的大括号{{}}
。
差值表达式渲染–字符串
先从最简单的入手,如何在页面中渲染一串文字
在学习 js 的时候,我们会这样做:
let str = "渲染一段文字";
let template = `<h2>${str}</h2>`;
// 后面省略一系列DOM操作
在 Vue 中,就显得轻松多了,首先在template
部分确定插值表达式的位置,并填充变量名:
<template>
<h2>{{title}}</h2>
</template>
在script
部分定义字符串变量:
<script>
// export default是固定格式,不需要纠结
export default {
// 模块的名字
name: "app",
// 页面中数据存放的地方
data() {
return {
title: "渲染一段文字"
};
}
};
</script>
如果你嫌弃文字太难看,你可以在样式部分给文字添加一点样式:
<!-- scope的意思表示这段样式只在本xxx.vue文件中生效,其他xxx.vue文件中不会生效,有锁定的意思 -->
<style scope>
h2 {
color: deeppink;
border: 1px solid #cccccc;
}
</style>
差值表达式渲染–数组
差值表达式还可以渲染数组,比如我们要做下面这个案例的时候就需要用到数组渲染:
HTML
代码和之前的写法是一样的,填充数据的时候可以采用数组下标的形式去取数据,代码如下:
<h2 class="title">{{title}}</h2>
<ul class="list">
<li>{{todoList[0]}}</li>
<li>{{todoList[1]}}</li>
<li>{{todoList[2]}}</li>
<li>{{todoList[3]}}</li>
<li>{{todoList[4]}}</li>
</ul>
提前预告一下,这里的
li
标签页不用重复去写,学习了v-for
就只需要写一行li
标签即可。
然后在 script 里面定义数组:
<script>
export default {
name: "app",
data() {
return {
title: "今日待完成事项",
todoList: [
"完成HTML标签学习",
"完成CSS文字样式学习",
"完成CSS盒模型学习",
"完成Flex布局学习",
"完成JavaScript入门学习"
]
};
}
};
</script>
data 中,变量和变量之间用逗号(,)隔开
最后需要修改一点样式,让文字和布局显得更美观一点(这里我们使用的是 sass 语法,需要在style
标签上添加lang="scss"
):
<style lang="scss" scope>
.title {
box-sizing: border-box;
width: 300px;
height: 30px;
margin: 0;
padding: 0 20px;
font-size: 18px;
font-weight: 700;
line-height: 30px;
color: white;
background: #fd6821;
border-radius: 6px;
}
.list {
list-style: none;
margin: 0;
padding: 0;
margin-top: 15px;
li {
box-sizing: border-box;
width: 300px;
height: 30px;
padding: 0 20px;
margin-bottom: 8px;
font-size: 14px;
line-height: 30px;
background: #8d999d;
color: white;
border-radius: 5px;
}
}
</style>
data、scope
在上面的代码中,有两个东西需要强调一下:
- data 方法里面用来存放数据或者全局变量,具体格式如上面的代码所示。 你可以将
title:'今日待完成事项'
理解成let title = '今日待完成事项'
- scope 你可以理解为锁,将 css 代码锁在本文件内,只在本文件内有用。
差值表达式–对象
如果我们要渲染一个班级名单列表,如下图所示:
根据要求,我们需要定义一个这样的变量:
<script>
export default {
name: "app",
data(){
return {
list:[
{
name:"张三",
grade:"三年级二班",
mark:290
},
{
name:"李四",
grade:"三年级二班",
mark:270
},
{
name:"王五",
grade:"三年级二班",
mark:270
}
]
}
}
};
</script>
关于声明式渲染,在基础阶段我们就学这么多。
处理用户输入
在这一节里我们要学到的是处理用户输入,用户输入就是 input、textarea,或者你还可以将 select、单选、复选等当作是用户输入来对待。
v-model(双向绑定)-- input
什么是双向绑定呢?我们用一个案例来说明一下,效果如下:
当我们在下面的 input 框内输入内容的时候,上面的框里内容会跟随改变。
定义一个基础的 HTML 代码结构:
<template>
<p class="page">{{message}}</p>
<input type="text" v-model="message" placeholder="请输入你想输入的内容" />
</template>
定义要用到的变量的变量:
<script>
export default {
name: "app",
data() {
return {
message: ""
};
}
};
</script>
什么是双向绑定呢?简单来说就是改变message
变量的值,input
标签内的值会变化,改变input
标签内的值,message
变量的值也会改变。
多行文本输入text-area
跟input
是一样的,只需要在text-area
标签上添加v-model
即可
<textarea v-model="message" placeholder="请在输入框内输入...">
v-model(双向绑定)-- checkbox(复选框)
除了 input、textarea 这种比较直观的用户输入行为,我们还可以将复选框作为一种用户输入行为
在复选框上使用双向绑定,来完成下图所示的一个案例:
来看一下核心代码:
<div class="food">
<div class="check-box">
<input type="checkbox" value="新奥尔良鸡腿堡" v-model="checkedGoods" />
</div>
<div class="food-name">新奥尔良鸡腿堡</div>
<div class="food-price">¥24</div>
</div>
<script>
export default {
name: "app",
data() {
return {
checkedGoods: []
};
}
};
</script>
关于用户输入呢,就先讲这三个比较常用的,其它的我们暂时先不去关注它。
处理用户事件
关于事件,我们在学习 js
的 DOM
的时候,已经接触过了,比如:
document.getElementById("btn").addEventListener("click", function () {
alert("Hello World");
});
麻烦吧?在 Vue 中,我们就不需要这么麻烦了。
在上面这段代码中我们进行了两步操作, 第一步:给元素添加点击事件 第二步:给点击事件添加方法
v-on:(事件绑定)
首先在 Vue 中做第一步:给元素添加点击事件
在 Vue 中不叫添加点击事件,叫事件绑定,事件绑定的语法如下:
<button v-on:click="add">按钮</button>
这样就给按钮注册了一个点击事件,当点击该按钮的时候,就会驱动add
方法,联系一下 js,是不是很明了?
Vue
为了方便用户开发,几乎每一个指令都会有一个简写模式,比如 v-on:
事件绑定指令的简写模式就是(@)符号,上面的代码可以改为:
<button @click="add">按钮</button>
今后我们在学习的过程中尽量使用简写形式。
methods(方法)
第二步:给点击事件添加方法
1. 抽离方法
这一步很简单,只需要将 js 代码中的匿名方法写在 Vue 规定的位置即可,为了照顾初学者,可以先一步步来,首先将匿名方法在 js 代码中抽离出来:
let alertFn = function () {
alert("Hello World");
};
document.getElementById("btn").addEventListener("click", alertFn);
2. 认识方法的书写位置
然后将抽离出来的alertFn
方法放到 Vue 中规定的位置,在 Vue 中,放方法的地方就是:
<script>
export default{
name:"app",
methods:{
// 在这里存放方法
}
}
</script>
3. 将抽离出的方法放在对应的位置
存放方法的形式是键值对key:value
的形式key
就是方法名,value
就是方法体,好了,完成最后一步吧。
<script>
export default{
name:"app",
methods:{
alertFn:function(){
alert("Hello World");
}
}
}
</script>
案例
下面我们来做一个简单的案例来将前面讲的知识串联起来,案例的功能就是点击按钮,数字+1,效果如下:
<template>
<p>{{ counter }}</p>
<button @click="add">点击</button>
</template>
<script>
export default {
name: "app",
data() {
return {
// 初始次数
counter:0
};
},
methods:{
add:function(){
// 这里的this指向当前的vue实例
this.counter++
}
}
};
</script>
注意:
this
指向的是当前 Vue 的实例,你不懂这个没关系,但是你要知道的是如果你要用在data
定义的变量,就必须在变量前面加this
@click="add"
的完整写法是@click="add()"
在括号里可以传递参数
<button @click="add">点击</button>
<!-- 等同于 -->
<button @click="add()">点击</button>
<!-- 当你的方法需要接收参数的时候,你可以将参数写在这个括号内 -->
<button @click="add(number)">点击</button>
相应的,你需要个 methods 里面的方法上添加形式参数
methods:{
add(number){
// 方法体
}
}
事件修饰符
关于事件,我们还需要了解的是事件修饰符。事件修饰符在使用中,通常情况下用到的可能只有三种:
- 阻止冒泡事件
<div @click.stop="fn2"></div>
- 捕获事件
<div class="div2" @click.capture="fn2"></div>
- 阻止默认事件
<div class="div2" @click.prevent="fn2"></div>
这几个事件修饰符和 js 中的事件修饰符的作用是一样的,只不过书写位置上有点变化,如果对其原理不清楚的,可以复习一下 js 课程中的内容。
监听数据变化
监听数据变化,在 Vue 中是通过侦听器来实现的,你也可以将它理解为监听器,时刻监听某个数据的变化。
watch 的基本用法
我们来通过改造之前的案例,来了解一下侦听器的基本用法
1. 侦听器的书写位置
在之前我们在 js 中添加了 data
、methods
,你会发现这两个属性都是以键值对的方式添加的,export default
就是一个对象,里面都是一对对的键值对,用逗号(,)隔开:
<script>
export default {
name: "app",
// 数据 key---data value---Function
data: function () {
return {};
},
// 方法 key---methods value---{}
methods: {}
};
</script>
添加一个侦听器进去,同样是以键值对的方式,顺序嘛,无所谓:
<script>
export default {
name: "app",
// 侦听器 key---watch value---{}
watch: {}
};
</script>
2. 侦听器的侦听对象
侦听器侦听的是什么呢?就是data
里面的变量,当变量发生变化的时候,侦听器开始运行,例如:
<script>
export default {
name: "app",
data: function () {
return {
count: 1
};
},
watch: {
count() {
console.log("count发生了变化");
}
}
};
</script>
**注意:**侦听器里面的方法count
一定要跟被侦听的变量名一致
3. 侦听器的运行时机
侦听器里面的count
要运行的话,count
变量的值必须发生变化,所以需要添加一个改变count
变量的方法add
:
<script>
export default {
name: "app",
data: function () {
return {
count: 1
};
},
methods: {
add: function () {
this.count++;
}
},
watch: {
count() {
console.log("count发生了变化");
}
}
};
</script>
此时当点击按钮,使count
变量的值发生改变,控制台就会打印count发生了变化
。
**注意:**在控制台打印出来的信息需要去浏览器的控制台中查看
控制台输出内容如下:
侦听器的进阶用法
获取前一次的值
在某些场景中,我们会需要上一次的数据,此时,侦听器就可以给我们两个值,旧值和新值。
在上一个案例的基础上,我们只需要添加一个参数,即可获取旧值,代码如下:
watch:{
inputValue(value,oldValue) {
// 第一个参数为新值,第二个参数为旧值,不能调换顺序
console.log(`新值:${value}`);
console.log(`旧值:${oldValue}`);
}
}
在上一个代码演示的基础上修改代码,查看控制台打印出来的内容,来验证一下侦听器的旧值和新值。
handler 方法和 immediate 属性
前面我们已经知道,当我们侦听的值没有发生改变的时候,是不会触发侦听器的,并且,页面第一次渲染的时候也不会触发侦听器。
但是现在我有个需求就是要让页面第一次渲染的时候就去触发侦听器呢?此时就要用到侦听器的immediate
属性。
在之前用的侦听器都是简写模式,实际上侦听器是一个对象,里面包含一个handler
方法和其他属性,immediate
属性就在其中:
<script>
export default {
name: "app",
watch: {
firstName: {
handler: function (newName, oldName) {
this.fullName = newName + " " + this.lastName;
},
immediate: true
}
}
};
</script>
当immediate
属性的值为true
时,不论数据是否变化,页面刷新以后,handler
方法就会运行。
观察页面刷新以后,handler
方法是否运行,将immediate
属性的值改为false
,并观察页面刷新以后handler
方法是否运行。