从HTML到现在一路跟过来的小伙伴们,坚持固然不容易,但我相信大家已经学到了不少,那么我们开始马不停蹄的进入前端的框架吧,下面讲的是Vue2,大家继续加油鸭!!!!
Vue2
Vue2官方文档地址,喜欢阅读文档的小伙伴可以点击进入官网。
1、Vue2 简介
Vue是什么?
官网的Vue的解释如下:
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue的两个特性:
1、数据驱动视图
- 数据的变化会驱动视图自动更新
- 好处:程序员只管把数据维护好,那么页面结构会被vue自动渲染出来
2、双向数据绑定
在网页中,form表单负责采集数据,Ajax负责提交数据
- js数据变化,会被自动渲染到页面上
- 页面上表单采集的数据发生变化,会被vue自动获取到,并更新到js数据中
注意:数据驱动视图和双向数据绑定的底层原理是MVVM(Model数据源、View视图、ViewModel就是vue的实例)
学了JS的小伙伴应该都知道,有很多操作都是基于DOM元素进行的,需要获取DOM元素,Vue则不需要获取DOM元素就可以对DOM元素进行操作,下面我们就进入Vue的正式学习吧!
1.1、Vue Devtools
在使用 Vue 时,推荐在你的浏览器上安装 Vue Devtools。它允许你在一个更友好的界面中审查和调试 Vue 应用。
1.2、安装引入Vue2
命令行运行
npm install vue@^2
或者引入Vue2
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
2、插值表达式
插值表达式 {{ }} 是一种Vue的模版语法
作用:利用表达式进行插值,渲染到页面中
语法:{{表达式}}
注意点:(1) 使用的数据必须存在
(2)支持的是表达式,而非语句
(3)不能在标签属性中使用{{}}插值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!--
构建用户界面
基于数据渲染页面
-->
<!-- 2 准备dom -->
<div id="app">{{ info}}-{{arr}}</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
info: 'hello vue',
arr: [1, 2, 3],
},
})
</script>
</html>
data中的数据最终会被添加到实例上
① 访问数据:“实例.属性名”
② 修改数据:“实例.属性名” = “值”
3、Vue指令
Vue 会根据不同的指令,针对标签实现不同的功能
指令:带有 v-前缀 的特殊标签属性, 不同的指令,完成不同的功能
3.1、v-if、v-else、v-else-if
v-if 作用:控制元素显示隐藏(条件渲染)
语法:v-if = “表达式” 表达式值true显示,false隐藏
v-else、v-else-if 作用:辅助v-if进行判断渲染
语法:v-else v-else-if = “表达式”
注意:需要紧挨着 v-if 一起使用
原理:基于条件判断,是否创建或移除元素节点
场景:要么显示,要么隐藏,不频繁切换的场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<p v-if="score > 90">A</p>
<p v-else-if="score >=80">B</p>
<p v-else="score >60">C</p>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
},
})
</script>
</html>
浏览器页面只显示了一个A
控制台查看元素,只创建了一个满足条件的p元素
3.2 v-show
作用:控制元素显示隐藏
语法:v-show = “表达式” 表达式值true显示,false隐藏
原理:切换 display:none / block控制显示隐藏
场景:频繁切换显示隐藏的场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<div v-show="5 == 3">456</div>
<div v-show="5 == 5">654</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
},
})
</script>
</html>
浏览器页面只显示了654
浏览器控制台查看元素,发现两个div都存在,只是具有不同的样式
这里就可以看出来,v-if与v-show都可以控住元素的显示和不显示,但是也存在区别:
v-if控制元素显示与隐藏,通过js创建dom元素或删除元素
v-show通过css的display显示与隐藏
区分:频繁切换元素显示与隐藏用v-show,其余可以用v-if
3.3、 v-on
作用:注册事件 = 添加监听 + 提供处理逻辑
语法:
① v-on:事件名 = “内联语句” => 简写: @事件名 = "内联语句 "
② v-on:事件名=“methods中的函数名” => 简写: @事件名 = “methods中的函数名”
调用函数时不传递参数,事件对象($event)就是默认的第一个形参
v-on 调用参数,当涉及到参数传递时 ,改写为 事件名 = “methods中的函数名(参数1,参数2)”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 2 准备dom -->
<div id="app">
<p>{{ num }}</p>
<button v-on:click="num++">+1</button>
<button @click="num--">-1</button>
<button @click="fn">按钮</button>
<button @click="fn2(10,$event)">按钮2</button>
</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
num: 0,
},
// 方法
methods: {
// fn: function() {}
fn(e) {
// 调用方法不传递任何参数,默认第一个形参就是事件对象
console.log(e)
console.log(this) // 指向vue实例
this.num += 10
console.log('按钮被点击')
// TODO
},
fn2(x, e) {
// 传递参数,实参通过$event
console.log(x, e)
},
},
})
</script>
</html>
3.4、v-for
作用:基于数组循环,多次渲染整个元素
遍历数组语法:v-for = “(item,index) in 数组“
item 表示每一项 index 表示下标
当参数只有一个时,可以省略括号
v-for 中的 key
语法:key属性 = “唯一标识”
key的作用:给元素添加的唯一标识,便于vue进行列表项的正确排序复用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 2 准备dom -->
<div id="app">
<a href="https://www.baidu.com">百度</a>
<a v-bind:href="link">京东</a>
<a :href="link" :x="10" y="20">京东</a>
<ul>
<li v-for="(item, index) in arr" :key="item.id">
{{index}}-{{ item.bookName }}
</li>
</ul>
<ul>
<li v-for="i in 8">{{i}}</li>
</ul>
</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
link: 'http://www.jd.com',
arr: [
{
id: 1,
bookName: '活法',
author: '稻盛和夫',
},
{
id: 2,
bookName: '羊脂球',
author: 'somebody',
},
{
id: 3,
bookName: '钢铁如何炼成的',
author: 'somebody',
},
],
}
})
</script>
</html>
注意点:1.key的值只能是字符串或数字类型
2.key的值必须具有唯一性
3.推荐使用id作为key的唯一值,不推荐使用index作为key
4.v-for 不建议与 v-if 一起使用,v-for优先级更高,消耗性能
3.5、 v-bind
作用:动态的设置html的标签属性 -> src、url、title ……
语法:v-bind:属性名 = “表达式” —> 简写 :属性名 = “表达式”
对于样式控制的增强
(1)、操作class
语法::class = “对象/数组”
①对象 --> 键就是类名,值是布尔值。如果值是true,有这个类,否则没有这个类
<div class='box' :class='{类名1:布尔值,类名2:布尔值}'></div>
②数组 --> 数组中所有的类,都会添加到盒子上,本质就是一个class列表
<div class='box' :class='[类名1,类名2,类名3]'></div>
(2)、操作style
语法::style = ‘样式对象’
<div class='box' :style='{css属性名1: css属性值,css属性名2: css属性值}'></div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.theme {
background-color: black;
}
.box {
font-size: 30px;
font-weight: 700;
}
.active {
border: 2px dashed pink;
}
</style>
</head>
<body>
<!-- 2 准备dom -->
<div id="app">
<div
class="box"
style="width: 100px; height: 100px; background-color: red"
></div>
<!-- 1 行内式 :style="样式对象" -->
<div
:style="{width:'100px',height:'100px', backgroundColor: 'blue'}"
></div>
<!-- 2 :class="['类名','类名']" -->
<div class="box" :class="[activeClass]" :style="styleObj">div</div>
<div class="box" :class="['active']" :style="styleObj">div</div>
<div class="box" :class="activeClass" :style="styleObj">div</div>
<div class="box" :class="'active'" :style="styleObj">div</div>
<div :class="['box', activeClass]" :style="styleObj">div1111</div>
<!-- <div class="box active" :style="styleObj">div</div> -->
<div>-----------------</div>
<!-- 3 :class="{类名1: 布尔值,类名2:布尔值}" -->
<div :class="{active: false}">div</div>
<div :class="{theme: bool}">div区域</div>
</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
info: 'hello vue',
arr: [1, 2, 3],
// 样式对象
styleObj: {
width: '200px',
height: '200px',
backgroundColor: 'red',
},
activeClass: 'active',
bool: true,
},
})
</script>
</html>
3.6、v-on
作用:注册事件 = 添加监听 + 提供处理逻辑
语法:
① v-on:事件名 = “内联语句” => 简写: @事件名 = "内联语句 "
② v-on:事件名=“methods中的函数名” => 简写: @事件名 = “methods中的函数名”
调用函数时不传递参数,事件对象($event)就是默认的第一个形参
v-on 调用参数,当涉及到参数传递时 ,改写为 事件名 = “methods中的函数名(参数1,参数2)”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 2 准备dom -->
<div id="app">
<p>{{ num }}</p>
<button v-on:click="num++">+1</button>
<button @click="num--">-1</button>
<button @click="fn">按钮</button>
<button @click="fn2(10,$event)">按钮2</button>
</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
num: 0,
},
// 方法
methods: {
// fn: function() {}
fn(e) {
// 调用方法不传递任何参数,默认第一个形参就是事件对象
console.log(e)
console.log(this) // 指向vue实例
this.num += 10
console.log('按钮被点击')
// TODO
},
fn2(x, e) {
// 传递参数,实参通过$event
console.log(x, e)
},
},
})
</script>
</html>
3.7、v-model
作用:给表单元素使用,双向数据绑定 —> 可以快速获取或设置表单元素内容
数据变化 —> 视图自己更新
视图变化 —> 数据自动更新
语法:v-model = “变量”
原理: v-model本质上是一个语法。例如应用在输入框上,就是 value属性和input事件的和写。
<template>
<div id='app'>
<input v-model='msg' type='text'>
<input :value='msg' @input='msg = $event.target.value' type='text'>
</div>
</template>
注意:$event用于在模版中,获取事件的形参
应用于其他表单元素
v-model会根据控件类型自动选取正确的方法来更新元素
输入框 input:text -----> :value + @input
文本域 textarea -----> :value + @input
复选框 -----> :checked + @change
单选框 -----> :checked + @change
下拉菜单 -----> :value + @change
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!--
v-model 双向绑定 用于表单元素
-->
<div id="app">
用户名 <input type="text" v-model="username" /> 密码
<input type="text" v-model="pwd" />
<!--
v-model="数据" 等价于 :value="数据" + @input="数据=$event.target.value"
-->
<input type="text" :value="username" @input="fn" />
<input type="checkbox" name="" id="" v-model="checked" />
<!-- <input
type="checkbox"
name=""
id=""
:checked="checked"
@change="checked = $event.target.checked"
/> -->
<button @click="login">登录</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
username: 'zs',
pwd: '',
checked: true,
},
methods: {
fn(e) {
this.username = e.target.value
},
login() {
console.log(this.username, this.pwd)
},
},
})
</script>
</body>
</html>
3.8、指令修饰符
通过 “.” 指明一些指令后缀,不同后缀封装了不同的处理操作 --> 简化代码
① 按键修饰符
@keyup.enter ----> 键盘回车监听
@keyup.esc -------> 键盘esc监听
② v-model修饰符
v-model.trim ----> 去除首位空格
v-model.number ------> 转数字
v-model.lazy ------------> 失去焦点,才收集数据
③ 事件修饰符
@事件名.stop —> 阻止冒泡
@事件名.prevent ----> 阻止默认行为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 按键修饰符.enter 只有按下Enter才触发 -->
<input type="text" @keyup.enter="fn" />
<!-- 指令修饰符 .trim 去掉首尾空格 .number转数字 -->
<input type="text" v-model.trim="username" />
<input type="text" v-model.number="age" />
<!-- 事件修饰符 .stop阻止冒泡-->
<div @click="fa">
<div @click.stop="son">son</div>
<a href="https://www.baidu.com" @click.stop.prevent="handleClick"
>百度</a
>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
username: '',
age: 0,
},
methods: {
fn(e) {
console.log(e)
console.log('ok')
},
fa() {
console.log('father')
},
son() {
console.log('son')
},
handleClick() {
alert('6666')
},
},
})
</script>
</body>
</html>
4、计算属性 computed
概念:基于现有的数据,计算出来的新属性。
优势:依赖的数据变化,才自动重新计算;计算属性,自带缓存效果
语法:①声明在 computed 配置项中,一个计算属性对应函数
②使用起来和普通属性一样使用 {{计算属性名}}
computed:{
计算属性名(){
基于现有的数据,编写求值逻辑
return 结果
}
}
计算属性完整写法
计算属性默认简写,只能访问,不能修改
如果要修改,需要写计算属性的完整写法
computed:{
计算属性名:{
get(){
一段代码逻辑(计算逻辑)
return 结果
}
set(修改的值){
一段代码逻辑(修改逻辑)
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 2 准备dom -->
<div id="app">
<p>计算属性 {{ avegeScore }}</p>
<p>计算属性 {{ avegeScore }}</p>
<p>计算属性 {{ avegeScore }}</p>
<p>方法 {{ avegeScore2() }}</p>
<p>方法 {{ avegeScore2() }}</p>
<p>方法 {{ avegeScore2() }}</p>
<button @click="avegeScore = 100">按钮</button>
</div>
</body>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
// 3 创建vue实例
new Vue({
// 元素
el: '#app',
// 数据
data: {
v: 0,
arr: [
{
id: 1,
name: 'zs',
score: 80,
},
{
id: 2,
name: 'ls',
score: 85,
},
{
id: 3,
name: 'wangwu',
score: 78,
},
],
},
// 计算属性-本质是一个函数
computed: {
// 不能与data中数据同名
// arr() {
// return 1
// },
/* avegeScore() {
console.log('computed')
const sum = this.arr.reduce((current, next) => {
return current + next.score
}, 0)
return (sum / this.arr.length).toFixed(2)
}, */
// 计算属性完整用法
// avegeScore: {
// 设置值走set
// set(newV) {
// this.v = newV
// },
// 使用计算属性走get
// get() {
// // const sum = this.arr.reduce((current, next) => {
// // return current + next.score
// // }, 0)
// // return (sum / this.arr.length).toFixed(2)
// return this.v
// },
// },
},
methods: {
avegeScore2() {
console.log('methods')
const sum = this.arr.reduce((current, next) => {
return current + next.score
}, 0)
return (sum / this.arr.length).toFixed(2)
},
},
})
</script>
</html>
computed 计算属性 VS methods 方法
(1)、computed 计算属性:
作用:封装了一段对于数据的处理,求得一个结果。
语法:写在computed配置项中;作为属性,直接使用 ----> this.计算属性 {{ 计算属性 }}
缓存特性(提升性能):计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变了,会自动重新计算 —> 并再次缓存
(2)、methods 方法:
作用:给实例提供一个方法,调用以处理业务逻辑
语法:写在methods配置中;作为方法,需要调用 --> this.方法名() {{ 方法名() }} @事件名=‘方法名’
5、侦听器 watch
作用:监视数据变化,执行一些业务逻辑 或 异步操作
语法:
① 简单写法 --> 简单类型数据,直接监视
watch:{
数据属性名(newValue,oldvalue){
一些业务逻辑 或 异步操作
},
'对象.属性名'(newValue,oldValue){
一些业务逻辑 或 异步操作
}
}
② 完整写法 --> 添加额外配置项
(1)deep:true , 对复杂类型深度监视
(2)immediate:true , 初始化立刻执行一次handler方法
watch:{
数据属性名:{
deep:true,
immediate:true,
handler(newValue){
一些业务逻辑 或 异步操作
}
}
}
watch的应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</div>
<!-- 1 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!',
},
watch: {
question() {
this.fn()
},
},
// 生命周期钩子函数 vue应用执行的时候自动帮我们调用
created() {
this.fn = _.debounce(this.getAnswer, 500)
},
methods: {
async getAnswer() {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
// 发请求
const {
data: { answer },
} = await axios.get('https://yesno.wtf/api')
this.answer = answer
},
},
})
</script>
</body>
</html>
后面我们接着讲Vue的生命周期以及后面的内容!!!