Vue2基础
【一】初识Vue
【1】什么是Vue
Vue 是一套用于构建用户界面的渐(逐渐)进(递进)式 JavaScript 框架
Vue 可以自底向上逐层应用,由国人尤雨溪开发
采用组件化模式,提高代码的复用率、让代码更好维护
声明式编码方式,让编码人员无需直接操作 DOM,提高开发效率
使用虚拟DOM + 优秀的 Diff 算法,尽量复用 DOM 节点
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
【2】引入Vue
本地方式引入
<script src="../js/vue.js"></script>
网络CDN方式引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
【3】Vue基本结构
在初学阶段,Vue 的结构由 容器 + 对象 两大部分构成
<body>
<div id="app">
{{name}}
{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app', // 这是Vue对象所绑定的容器对象,一般使用css选择器绑定
data: { // data用于存储数据
name: 'green',
age: 18
}
})
</script>
【二】基础知识
【1】模板语法
插值语法
<body>
<div id="app">
{{name}}
<br>
{{age}}
<br>
{{hobby}}|{{hobby[0]}} // 数组只能用中括号取值
<br>
{{obj}}|{{obj.name}}|{{obj["name"]}} // 对象可以用中括号或者点属性取值
<br>
{{link}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'green',
age: 18,
hobby: ['洗衣服', '做饭', '打游戏'],
obj: {name: "hqq", age: 22, hobby: ['抽烟', '喝酒', '洗脚']},
link: '<a href="https://meizi5.com">点击看美女</a>'
}
})
</script>
</body>
指令语法
<div id="root">
<!-- v-bind 可以简写为 : -->
<a v-bind:href="url">点我去百度 - 完整写法</a>
<a :href="url">点我去百度 - 简略写法</a>
</div>
<script>
new Vue({
el: '#root',
data: {
url: 'https://www.baidu.com'
}
})
</script>
总结
插值语法
功能:用于解析标签体中的内容
写法:{{xxxx}},其中 xxxx 是 js 表达式,且可以直接读取到 data 中的所有属性
指令语法
功能:用于解析标签(包括:标签属性,标签体内容,绑定事件)
【2】数据绑定
单向绑定:str变---》input框变,input框变---》str不变
单向绑定:str变---》input框变,input框变---》str也变
<div id="app">
单向绑定 <input type="text" :value="str">
双向绑定 <input type="text" v-model:value="str">
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
str: '炎帝萧炎'
}
})
</script>
</body>
总结
总结:
单向绑定(v-bind):数据只能由 data 流向页面
双向绑定(v-model)
数据既能从 data 流向页面,也能从页面流向 data
双向绑定一般都应用在表单类元素上(input、select...)
v-model:value 可以简写为 v-model,因为 v-model 默认绑定的就是 value 属性
【3】事件指令
es6的对象写法
// es6 的对象写法
var hobby=['抽烟','烫头']
var obj={
'name':'hqq',
age:19, // 键值可以不带引号
hobby, // 可以直接省略键名,在有定义的情况下
showName() {
console.log(this.name)
// 函数可以省略:function
}
}
函数传参数问题
<body>
<div id="app">
<button v-on:click="showFunc1">不传参数,函数有参数(会自动把当前事件传入)</button>
<button v-on:click="showFunc2(name)">传参数,函数有参数(正常输出)</button>
<button v-on:click="showFunc3($event)">传参数,函数有参数,把事件对象传入(正常输出)</button>
<button v-on:click="showFunc4()">传参数,函数有多个参数,少传参数(少传就输出传入的,多传就不关多出来的)</button>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'green'
},
methods: {
showFunc1(event) {
console.log(event)
},
showFunc2(param) {
console.log(param)
},
showFunc3(event) {
console.log(event)
},
showFunc4(a,b,c) {
console.log(a,b,c)
}
}
})
</script>
【4】属性指令
1. 标签上有属性 如:
img的src属性,a标签的href属性
2. 属性指令的作用就是使用变量动态的设置属性的值
3. 使用方法
v-bind:属性名='变量'
简写
:属性名='变量'
动态切换美女图片案例
<body>
<div id="app">
<button @click="handleClick">点击切换自动切换美女</button>
<img :src="src" alt="">
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
list: ['/img/1.jpg', '/img/2.jpg', '/img/3.jpg'],
src: '',
index: 0,
flag: false,
t: null
},
methods: {
handleChange() {
console.log(this.index)
this.src = this.list[this.index]
this.index += 1
if (this.index === 3) {
this.index = 0
}
},
handleClick() {
if (this.flag === false) {
this.t = setInterval(this.handleChange, 1000)
this.flag = true
} else {
clearInterval(this.t)
this.flag = false
}
}
}
})
</script>
</body>
补充:js中的计时器
js 定时器有以下两个方法:
setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
setTimeout() :在指定的毫秒数后调用函数或计算表达式。
语法
setInterval(code,millisec,lang)
code 必需。要调用的函数或要执行的代码串。
millisec 必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。
lang 可选。 JScript | VBScript | JavaScript
【5】style和class
# 1 class 可以绑定 字符串,数组,对象
字符串: 'div1 div2'---》字符串替换控制样式
数组:['div1','div2']--->追加数组,删除数组控制样式
对象:{div1: true, div2: true, div3: true, div4: false}--》通过true和false控制样式
# 2 style 可以绑定 字符串,数组,对象
字符串'background-color: green;height: 300px;width: 300px'---》字符串替换控制样式
数组:[{'background-color': 'green'}, {height: '300px'}, {width: '300px'}]--->追加数组,删除数组控制样式
对象:{backgroundColor: 'green', height: '330px', width: '300px'} --》通过根据key修改value控制样式
# 3 坑:以后如果改了对象,或数组,发现页面没有变化,实际上值被真正的改了
Vue.set(this.style_list,3,{'margin':'auto'})
【6】条件渲染
v-if v-else-if v-else
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./vue/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<h1>条件判断</h1>
<h2>分数是:{{score}}</h2>
<h3 v-if="score>=90&&score<=100">优秀</h3>
<h3 v-else-if="score>=80&&score<90">良好</h3>
<h3 v-else-if="score>=60&&score<80">及格</h3>
<h3 v-else>不及格</h3>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
score: 99
}
})
</script>
</html>
【7】列表渲染
通过使用v-for循环显示多条数据
购物车案例
<body>
<div class="container text-center" id="app">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">购物车</h1>
<button class="btn btn-success" @click="showGood">加载购物车</button>
<div v-if="!good_list">空空如也</div>
<table class="table table-info">
<thead>
<tr>
<th scope="col">商品ID</th>
<th scope="col">商品名称</th>
<th scope="col">商品数量</th>
<th scope="col">商品价格</th>
<th scope="col">商品图片</th>
</tr>
</thead>
<tbody>
<tr v-for="good in good_list">
<th scope="row">{{good.id}}</th>
<td>{{good.name}}</td>
<td>{{good.number}}</td>
<td>{{good.price}}</td>
<td><img v-bind:src="good_img" alt="" v-bind:style="style_dic"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
good_list: null,
good_img: null,
style_dic: {}
},
methods: {
showGood() {
this.good_list = [
{'id': 1, 'name': '短裙', 'number': 20, 'price': 22},
{'id': 2, 'name': '黑丝', 'number': 34, 'price': 43},
{'id': 3, 'name': '白丝', 'number': 55, 'price': 12},
{'id': 4, 'name': '过膝袜', 'number': 19, 'price': 5},
{'id': 5, 'name': '马油袜', 'number': 39, 'price': 3},
]
this.good_img = '/img/1.jpg'
Vue.set(this.style_dic, 'width', '30px')
Vue.set(this.style_dic, 'height', '30px')
}
}
})
</script>
</body>
for循环不同数据类型
<body>
<div id="app">
<h1>for循环字符串</h1>
<p>默认循环字符,还可以加入第二个参数,循环索引</p>
<p v-for="(item,index) in str">字符--->{{item}} 索引--->{{index}}</p>
<h1>for循环数字</h1>
<p>从1开始循环到最后一个数字(包括最后一个数字)也可以循环索引</p>
<p v-for="(item,index) in num">数字--->{{item}} 索引--->{{index}}</p>
<h1>循环数组</h1>
<p>默认循环元素,还可以加入第二个参数,循环索引</p>
<p v-for="(item,index) in list">元素--->{{item}} 索引--->{{index}}</p>
<h1>循环对象</h1>
<p>默认循环value值,还可以加入第二个参数,循环键值</p>
<p v-for="(value,key) in obj">值--->{{value}} 键--->{{key}}</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
list: ['张雪峰', '暴叔', '吉田'],
str: 'hello word',
obj: {name: 'green', age: 18},
num: 10
}
})
</script>
</body>
标签内加入key属性
#1 以后写v-for,都要在标签上加 :key="key" ,key必须唯一
# 2 这样做可以提高虚拟dom的替换效率
【8】事件处理
# 1 input 标签的事件处理
input 当输入框进行输入的时候 触发的事件
change 当元素的值发生改变时 触发的事件
blur 当输入框失去焦点的时候 触发的事件
focus 当获得焦点的时候 触发的事件
<body>
<div id="app">
<input type="text" @input="handleInput($event)" value="当输入框进行输入的时候 触发的事件"><br>
<input type="text" @change="handleChange" value="当元素的值发生改变时 触发的事件"><br>
<input type="text" @blur="handleBlur" :value="inputValue"><br>
<input type="text" @focus="handleFocus" :value="inputValue"><br>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
inputValue: ''
},
methods: {
handleInput(event) {
console.log(event.data)
},
handleChange() {
alert('发生改变了')
},
handleBlur() {
this.inputValue = '失去焦点了'
},
handleFocus(){
this.inputValue = '得到焦点了'
}
}
})
</script>
</body>
过滤小案例
<body>
<div id="app" class="container-fluid">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">过滤小案例</h1>
<p class="text-center">搜索框</p>
<input type="email" class="form-control" v-model:value="kewWord" @input="handleInput">
<table class="table">
<tr v-for="item in list">
<td class="text-center">{{item}}</td>
</tr>
</table>
</div>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
dataList: ['黑丝', '黑丝袜', '黑丝连体袜', '吊带', '吊带蝴蝶结', 'black', 'blac', 'bla'],
kewWord: 'hahah',
list: null
},
methods: {
handleInput() {
let _this = this
this.list = this.dataList.filter(function (item) {
return item.indexOf(_this.kewWord) >= 0
})
}
}
})
</script>
</body>
# 箭头函数优化代码写法
methods: {
handleInput() {
this.list = this.dataList.filter((item)=> item.indexOf(this.kewWord) >= 0
)
}
}
// 流程
核心是 要通过输入框的内容过滤数据列表
输入框的内容可以通过双向绑定得到
通过filter函数过滤,它可以将数组里的一个个元素分别进行校验,如果不通过返回flase,通过返回true
通过 indexOf 方法校验当前输入框的内容和数据数组里的元素是否匹配 如果匹配返回大于0的数,不匹配返回-1
补充:js中的filter函数
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
注意: filter() 不会对空数组进行检测。
注意: filter() 不会改变原始数组。
语法
array.filter(function(currentValue,index,arr), thisValue)
currentValue 当前从array取出校验的元素
index 当前取出的元素的索引
arr 当前元素的来源
补充:es6语法箭头函数
<!-- 初始匿名函数写法-->
let name = 'green'
let f = function (name){
return name + 'nb'
}
console.log(f(name))
// 箭头函数写法,去掉function,在括号和大括号中间加上=>
let f = (name) => {
return name + 'nb'
}
console.log(f(name))
// 当函数只需要传一个参数时,可以不用 用括号把参数括起来
let f = name => {
return name + 'nb'
}
console.log(f(name))
// 当返回值只有一行代码时,可以不用写return 和 大括号
let f = name => name + 'nb'
console.log(f(name))
为什么要写箭头函数?
箭头函数是为了解决function函数的this指向问题,
箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
【9】事件修饰符
在Vue中,事件修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。
在Vue中事件修饰符主要有:
.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡
.prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
.capture:与事件冒泡的方向相反,事件捕获由外到内
.self:只会触发自己范围内的事件,不包含子元素
.once:只会触发一次
【10】jsfor循环的方式
普通的索引循环
<script>
<!-- 普通的索引循环-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for(let i=0 ;i<arr.length;i++){
console.log(arr[i])
}
</script>
基于迭代的off循环
<script>
<!-- 迭代off循环-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for (let item of arr) { // item就是数组里面的一个个元素
console.log(item)
}
</script>
基于迭代的in循环
<script>
<!-- 迭代in循环-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
for (let index in arr) { // index是索引
console.log(arr[index])
}
</script>
数组的forEach方法循环
<script>
<!-- 数组的forEach方法循环-->
let arr = [18, 'green', {name: 'hqq', age: 22}]
arr.forEach((value,index,array)=>{ // 分别是元素,索引,数据源数组
console.log(value,index,array)
})
</script>
【11】按键修饰符
#1 按下某个键盘,触发事件,通过修饰控制只有按下某个键,才触发事件
#2 keyCode对应表--》按键修饰符
https://www.cnblogs.com/841019rossi/p/16808455.html
<body>
<div id="app">
<button @keyup.enter="handleEnter">按回车有惊喜</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data:{},
methods:{
handleEnter(){
alert('回车被按了')
}
}
})
</script>
</body>
【12】表单控制
# 1 checkbox v-model 绑定
-布尔 :选中没选中
-数组:多选
# 2 radio:
-字符串:value的值
购物车小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-/mhDoLbDldZc3qpsJHpLogda//BVZbgYuw6kof4u2FrCedxOtgRZDTHgHUhOCVim"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app" class="container">
<div class="row">
<div class="col-6 offset-3">
<h1 class="text-center">图书商城</h1>
<p class="text-center">
<button class="btn btn-success" @click.once="handleLoad">加载购物车</button>
</p>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="搜索书名"
aria-label="Recipient's username" aria-describedby="button-addon2" v-model="searchText">
<button class="btn btn-outline-secondary" type="button" id="button-addon2" @click="handleSearch" >搜索
</button>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">书名</th>
<th scope="col">作者</th>
<th scope="col">价格</th>
<th scope="col">数量</th>
<th scope="col"><p>全选/全不选 <input type="checkbox" v-model="checkAll" @change="handleChange"></p>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(book,index) in showList">
<th scope="row">{{index + 1}}</th>
<td>{{book.title}}</td>
<td>{{book.author}}</td>
<td>{{book.Price}}</td>
<td>
<button class="btn" @click="handleSub(book)">-</button>
{{book.num}}
<button class="btn" @click="handleAdd(book)">+</button>
</td>
<td><input type="checkbox" v-model="checkList" @change="handleSum" :value="book"></td>
</tr>
</tbody>
</table>
<p>总价格</p>
<input type="text" class="form-control" readonly :value="getSum">
</div>
</div>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
bookList: [],
checkList: [],
checkAll: null,
searchText: '',
showList: []
},
methods: {
handleLoad() {
axios.get('http://127.0.0.1:8000/api/v1/book/')
.then((response) => {
for (const responseElement of response.data.results) {
responseElement.num = 0
}
this.bookList = response.data.results
})
},
handleAdd(book) {
book.num += 1
this.handleSum()
},
handleSub(book) {
if (!book.num) {
return
}
book.num -= 1
this.handleSum()
},
handleSum() {
this.checkAll = (this.checkList.length === this.bookList.length)
},
handleChange() {
if (this.checkAll) {
this.checkList = this.bookList
} else {
this.checkList = []
}
},
handleSearch() {
this.showList = this.bookList.filter((book) => book.title.indexOf(this.searchText) >= 0)
}
},
computed: {
getSum() {
let total = 0
for (let book of this.checkList) {
total += book.num * book.Price
}
return total
}
}
})
</script>
</html>
【13】v-model进阶
v-model 之 lazy、number、trim
lazy:等待input框的数据绑定失去焦点之后再变化
number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留
trim:去除首位的空格
【14】vue与ajax
vue的数据与后端进行交互的ajax方式有:
原生js的ajax(不常用)
jquery封装的ajax(不常用)
H5自带的fetch (可能用)
vue的axios(Vue作者推荐用)
原生js的ajax
<!DOCTYPE html>
<html>
<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>
</body>
<script>
/* ajax */
//post数据传递,一般需要接口文档,自己用node写也是可以的
//创建ajax
var xhr = new XMLHttpRequest;
//请求地址
xhr.open('post', 'url');
//请求头
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
//因为ajax异步send还是写这里比较好
xhr.send('name=zhangsan&age=18')
xhr.onreadystatechange = function(){
if (xhr.readyState === 4){
if (xhr.status>=200 && xhr.status<300){
var res = xhr.responseText;
console.log(res);
}
}
}
</script>
</html>
jquery封装的ajax
因为jquery有比较完整的ajax封装,但它主要是操作DOM和Bom,所以一般也不怎么用,作为拓展吧
<!DOCTYPE html>
<html>
<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">
<!-- bootcdn的镜像也可以自己下载jquery库-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<title>Document</title>
</head>
<body>
</body>
<script>
/* jquery */
$.ajax({
method:'post',
url:'url',
// // dataType:"",
data:{
name:'zhangsan',
age:18
},
success:res=>{
console.log(res);
},
// // error:err=>{
// // }
})
</script>
</html>
H5自带的fetch
H5自带的fetch封装的ajax也是比较好的,现在市面上还有些公司在用
<!DOCTYPE html>
<html>
<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>
</body>
<script>
/* fetch */
//get,返回值是对象所以需要调用then()方法,调用出来
fetch('url?name=zhangsan&age=18').then(res=>res.text()).then(res=>{
console.log(res);
})
//post,body里还是不能用对象
fetch('url',{
method:'post',
body:'name=zhangsan&age=14',
headers: {
"content-type": 'application/x-www-form-urlencoded'
}
//转json数据格式
}).then(res=>res.json()).then(res=>{
console.log(res);
})
</script>
</html>
axios库
主要使用的数据请求方式,因为作者推荐,作者都推荐了嘛,最后还得是看公司,没要求最好还是axios
使用需要下载axios插件,使用方法详见官网:axios官网
<!DOCTYPE html>
<html>
<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>
</body>
<script src="./node_modules/axios/dist/axios.js"></script>
<script>
/* axios */
//设置全局令牌,发送请求就不用特地带令牌了
axios.defaults.headers['authorization'] = 'token'
//get,可以设置全局地址提高代码复用率,减少自己写代码,就不用每个都写这么长的地址,嘿嘿
axios.defaults.baseURL='url'
axios.get('third', {
params: {
name: 'lisi',
age: 20
}
}).then(res => {
console.log(res.data);
})
//post
axios.post('/fourth', 'name=a&age=12').then(res => {
console.log(res);
})
</script>
</html>
【15】计算属性
# 1 计算属性是基于它们的依赖进行缓存的
# 2 计算属性只有在它的相关依赖发生改变时才会重新求值
# 3 计算属性就像Python中的property,可以把方法/函数伪装成属性
# 4 写在computed中,必须返回值--》返回值才是属性
-以后把他当属性用
-可以被for循环
通过计算属性实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="nameText"> ---> {{upperFirst}}
</div>
<script>
let vm = new Vue({
el: '#app',
data:{
nameText:'',
},
methods:{},
computed:{
upperFirst(){
return this.nameText.substring(0, 1).toUpperCase() + this.nameText.substring(1)
}
}
})
</script>
</body>
</html>
【16】监听属性
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
需要监听哪个属性,就在watch里面写哪个属性,只要这个属性发送改变,就会自动执行这个方法
小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-/mhDoLbDldZc3qpsJHpLogda//BVZbgYuw6kof4u2FrCedxOtgRZDTHgHUhOCVim"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<button class="btn btn-success" @click="res='python'">python</button>
<button class="btn btn-info" @click="res='java'">java</button>
<button class="btn btn-danger" @click="res='go'">go</button>
result --->{{res}}
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
res: ''
},
watch:{ // 想要监听哪个参数就在watch里面写哪个参数,当这个参数发生变化就会自动执行
// before改变前,back改变后 这两参数可填可不填
res(before,back){
console.log(back,before)
}
}
})
</script>
</body>
</html>
【17】生命周期
vue生命周期分别有创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载利用钩子函数完成对应的项目效果
beforeCreate( 创建前 )
在实例化之后,数据的观测和事件的配置之前的时候调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据
created ( 创建后)
在创建之后使用,主要用于数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始.
beforeMount (挂载前)
用于在挂载之前使用,在这个阶段是获取不到dom操作的,把data里面的数据和模板生成html,完成了data等初始化,注意此时还没有挂在html到页面上
mount (挂载后)
用于挂载之后使用,在这个时候可以获取到dom操作,比如可以获取到ref等,操作的dom, 在这个时候只能调用一次ajax,在这个时候el和data都可以获取的到
beforeUpdate (更新前)
在数据更新之前被调用,发生在虚拟DOM重新渲染,可以在该钩子中进一步地更改状态,不会触发重复渲染过程
updated (更新后)
在由于数据更改导致地虚拟DOM重新渲染会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,但是在服务器端渲染期间不被调用,可以用于监听某些数据的时候使用钩子
beforeDestroy(销毁前)
在这个时候还是可以用this来获取,可以用于销毁计时器时候使用,为了防止跳转到其它页面该事件还在执行,还可以清除dom事件等
destroy(销毁后)
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<child v-if="showChild"></child>
<button @click="showChild=!showChild">点我消失</button>
</div>
</body>
<script>
Vue.component('Child', {
template: `
<div>
<button @click="handleClick">{{ title }}</button>
</div>`,
data() {
return {
title: 'hello word'
}
},
methods: {
handleClick() {
alert(this.title)
this.title = '你好世界'
},
},
// 在创建实例之前执行 this.title不会有值 this.$el不会有值
beforeCreate() {
console.log('beforeCreate')
console.log(this.title)
console.log(this.$el)
},
// 创建实例时执行 this.$el不会有值
created() {
console.log('Create')
console.log(this.title)
console.log(this.$el)
},
// 挂载之前执行 this.$el不会有值
beforeMount() {
console.log('beforeMount')
console.log(this.title)
console.log(this.$el)
},
mounted() {
console.log('mounted')
console.log(this.title)
console.log(this.$el)
},
// 在没有更新数据就不会执行, 有更新的话会在更新之前执行
beforeUpdate() {
console.log('beforeUpdate')
console.log(this.title)
console.log(this.$el)
},
// // 在没有更新数据就不会执行, 有更新的话会在更新之后执行
updated() {
console.log('Updated')
console.log(this.title)
console.log(this.$el)
},
// 在没有执行删除就不会执行, 有删除操作的话会在删除之前执行
beforeDestroy() {
console.log('beforeDestroy')
console.log(this.title)
console.log(this.$el)
},
// 在没有执行删除就不会执行, 有删除操作的话会在删除之后执行
destroyed() {
console.log('destroyed')
console.log(this.title)
console.log(this.$el)
}
})
let vm = new Vue({
el: '#app',
data: {
showChild: true
},
methods: {}
})
</script>
</html>
【18】组件的使用
组件分为局部组件和全局组件,全局组件可以在根组件的任意位置使用,局部组件只能使用在父组件里面
组件中的数据,事件都是独立的
全局组件的书写
<body>
<div id="app">
<Child></Child>
</div>
</body>
<script>
// 全局组件的书写
Vue.component('Child', {
// 需要通过template挂载
template: `
<div><h1>我是全局组件</h1>
<p>{{ message }}</p>
<button @click="handleClick">点我显示名字</button>
</div>`,
// data需要写成一个函数 然后把值写在函数的返回值里
data() {
return {
message: '需要写在根组件里'
}
},
// 方法的写法和根组件的写法一致
methods: {
handleClick() {
this.message = 'green'
}
}
})
let vm = new Vue({
el: '#app',
})
</script>
局部组件的书写
<body>
<div id="app">
<p>{{message}}</p>
<button @click="handleClick">点击显示根组件名字</button>
<Child></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
message: '我是根组件'
},
methods: {
handleClick() {
this.message = 'green'
}
},
// 在根组件中定义局部组件,这里以根组件为例子,定义在哪里的局部组件,就只能在哪里使用
components:{
Child:{
template:`<div><h1>我是局部组件,根组件的子组件</h1><button @click="handleClick">点我弹窗</button></div>`,
data(){
return{
message:'我是子组件Child'
}
},
methods: {
handleClick(){
alert(this.message)
}
}
}
}
})
</script>
【19】组件中通信
各个组件的数据都是独立的,要想实现各个组件的数据互通,需要用到一些特定的方法
父传子
<body>
<div id="app">
<button @click="handleClick">点击给在子组件发消息</button>
<!-- 1.在子组件标签中绑定数据属性-->
<Child :message="message"></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
message: ''
},
methods: {
handleClick() {
this.message = '我是来自父组件的消息--->你好'
}
},
// 定义子组件
components: {
Child: {
template: `
<div><h1>我是子组件Child</h1>
<p>来自父组件的消息---->{{ message }}</p></div>`,
// 2.在子组件中定义props,将子组件标签中定义的数据属性键值填入props的数组
props: ['message']
}
}
})
</script>
子传父
<body>
<div id="app">
<h1>我是父组件</h1>
<img :src="src" width="250px" height="300px" alt="" v-if="src">
<!-- 子组件给父组件传参数,需要给子组件标签绑定一个自定义事件-->
<Child @event="handleEvent"></Child>
</div>
</body>
<script>
let em = new Vue({
el: '#app',
data: {
src: ''
},
methods: {
handleEvent(src) {
this.src = src
}
},
components: {
Child: {
template: `
<div><h1>我是子组件</h1><img :src="src" alt="" width="250px" height="300px" v-if="src">
<button @click="handleClick">点击把图片传到父组件</button>
</div>`,
data() {
return {
src: './img/1.jpg'
}
},
methods: {
handleClick() {
// 通过this.$emit('event', this.src),第一个参数就是自定义事件的名称,第二个参数就是传递的参数
this.$emit('event', this.src)
this.src = ''
}
}
}
}
})
</script>
【20】ref属性
ref是Vue2中一个重要的属性,用于在组件中对DOM元素或者子组件的引用。通过ref,可以在某个组件的内部直接访问DOM元素或者它的子组件。
在Vue2中可以将ref添加到元素,组件或者子组件的标签上,然后可以通过组件实例的$refs对象来访问这些引用
<body>
<div id="app">
<h1>我是父组件</h1>
<button @click="handleClick" ref="button">点我看控制台</button>
<Child ref="child"></Child>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {},
methods: {
handleClick() {
// this是当前Vue的实例
// this.$refs是一个对象,里面包含了所有的有ref属性的标签的dom对象或者组件对象
// 1.拿到子组件的属性
console.log(this.$refs.child.message)
// 2.修改子组件的属性
this.$refs.child.message = '我是修改后的消息'
// 3.调用子组件的函数
this.$refs.child.handleClick('我是来自父组件的参数')
// 4.给子组件的函数传参数
}
},
components: {
Child: {
template: `
<div ><h1>我是子组件</h1> <button @click="handleClick">点我看看</button><p>{{message}}</p></div>`,
data() {
return {
message: '我是来自子组件的消息'
}
},
methods: {
handleClick(name){
console.log('我被父组件的事件调用了')
console.log(name)
}
}
}
}
})
</script>
【21】动态组件
动态组件,就是实现动态切换的组件
记住以下三点,就能掌握动态组件
① 利用 <component/>
元素的 is
属性
② is
属性应该用 v-bind
修饰(可以简写为 :
)
③ is
属性应该传入注册的组件名
<body>
<div id="app">
<button @click="name='Girl1'">美女1</button>
<button @click="name='Girl2'">美女2</button>
<button @click="name='Girl3'">美女3</button>
<!-- component是一个万能组件,他的is属性就决定了它是哪一个组件 -->
<component :is="name"></component>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
name:''
}
})
Vue.component('Girl1', {
template: `<div><h1>美女1</h1><img src="./img/1.jpg" alt=""></div>`
})
Vue.component('Girl2', {
template: `<div><h1>美女2</h1><img src="./img/2.jpg" alt=""></div>`
})
Vue.component('Girl3', {
template: `<div><h1>美女3</h1><img src="./img/3.jpg" alt=""></div>`
})
</script>
【22】keep-alive
在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。
也就是说,keepalive
是 Vue
内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存
<keep-alive>
是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
<!--被keepalive包含的组件会被缓存-->
<keep-alive>
<component><component />
</keep-alive>
【23】插槽
正常情况下,如果已经写好了一个组件,并且想要往组件里面添加别的东西,就只能修改组件内容,拓展性很差
所以就出现了插槽的概念,只需要在模板中可能需要更改的地方加上<slot></slot>
,后续想要更新内容的时候直接在html里面加就行