目录
二.vue3基础
5.事件处理器
5-1 事件处理器 - 告别原生事件
5-2 事件修饰符 - 事件偷懒符?
6.表单控件绑定
6-1表单输入绑定-一根绳上的蚂蚱
6-2购物车案例
6-3表单修饰符
7.计算属性
7-1计算属性-很聪明,会缓存
7-2 可写计算属性
7-3之前案例的小改造
7-4侦听器watch的对比
7-5深层侦听器
8.数据请求
8-1Fetch
8-2 axios
9.过滤器
9-1vue3过滤器不支持了-怎么办?
二.vue3基础
5.事件处理器
5-1 事件处理器 - 告别原生事件
内联事件处理器
<button @click="count++">Add 1</button>
<button @click="test('hello',$event)">test hello</button>
方法事件处理器
<button @click="test">test</button>
<button @click="(e)=>test(e)">test hello</button>
5-2 事件修饰符 - 事件偷懒符?
Vue为v-on提供了事件修饰符。修饰符是用.表示的指令后缀,包含以下这些:
- .stop 阻止冒泡
- .prevent 阻止默认行为
- .self 只有点击自己才触发
- .capture 捕获阶段触发
- .once 只触发一次
- .passive
按键修饰符
Vue为一些常用的按键提供了别名:
- .enter
- .tab
- .delete(捕获“Delete”和“Backspace”两个按键)
- .esc
- .space
- .up
- .down
- .left
- .right
<body>
<div id="app">
<ul @click.self="handleUlClick">
<li @click.stop="test">111</li>
<li @click="test2">22</li>
</ul>
<input type="text" @keyup.a='test2'>
<input type="text" @keyup.enter.ctrl='test2'>
</div>
</body>
<script>
const { createApp } = Vue
let obj = {
data() {
return {
}
},
methods: {
test2() {
console.log(222);
},
test() {
console.log(11);
},
handleUlClick() {
console.log('ul');
}
}
}
createApp(obj).mount('#app')
6.表单控件绑定
6-1表单输入绑定-一根绳上的蚂蚱
普通文本
<input v-model="message" placeholder="editme" />
复选框
<input type="checkbox" id="checkbox" v-model="checked" />
单选框
<div>Picked:{{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" /
选择器
<div id="app">
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option value="a">A</option>
<option>B</option>
<option>C</option>
</select>
</div>
6-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>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<style>
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border: 1px solid lightgray;
}
li img {
width: 100px;
}
</style>
<body>
<div id="app">
<ul>
<li>
<div>
<input type="checkbox" v-model="isAllChecked" @change="handleAllChange">
<span>全选/全不选</span>
</div>
</li>
<template v-if="datalist.length">
<li v-for='item in datalist' :key='item.id'>
<div>
<input type="checkbox" v-model="checkList" :value="item" @change="handleItemChange">
</div>
<div>
<img :src="item.poster">
</div>
<div>
<div>{{item.title}}</div>
<div style="color:red;">价格:{{item.price}}</div>
</div>
<div>
<!-- 虽然操作的是datalist.item 但是 checkList的item存放的是datalist的引用 所有sum函数会执行-->
<button @click="item.number--" :disabled="item.number===1">-</button>
{{item.number}}
<button @click="item.number++" :disabled="item.number===item.limit">+</button>
</div>
<div>
<button @click="handleDel(index,item.id)">删除</button>
</div>
</li>
</template>
<li v-else>购物车空空如也</li>
<li>
<!-- checkList 变化 sum函数就会执行 -->
<div>总金额:{{ sum()}}</div>
</li>
</ul>
</div>
</body>
<script>
const { createApp } = Vue
let obj = {
data() {
return {
isAllChecked: false,
checkList: [],//勾选的商品列表
datalist: [{
id: 1,
title: "商品1",
price: 10,
number: 1,
poster: "https://p0.meituan.net/movie/dc2fed6001e809e4553f90cc6fad9a59245170.jpg@1l_1e_1c_128w_180h",
limit: 5
},
{
id: 2,
title: "商品2",
price: 20,
number: 2,
poster: "https://p0.meituan.net/moviemachine/3084e88f63eef2c6a0df576153a3fad0327782.jpg@1l_1e_1c_128w_180h",
limit: 6
},
{
id: 3,
title: "商品3",
price: 30,
number: 3,
poster: "https://p0.meituan.net/movie/897b8364755949226995144bfc2261ee4493381.jpg@1l_1e_1c_128w_180h",
limit: 7
}
]
}
},
methods: {
sum() {
// var total = 0
// for(var i=0;i<this.checkList.length;i++){
// total+=this.checkList[i].number*this.checkList[i].price
// }
// return total
//reduce
return this.checkList.reduce((total, item) => total + item.price * item.number, 0)
},
//处理删除
handleDel(index, id) {
this.datalist.splice(index, 1)
//同步更新checklist
this.checkList = this.checkList.filter(item => item.id !== id)
//同步全选
this.handleItemChange()
},
handleAllChange() {
this.checkList = this.isAllChecked ? this.datalist : []
},
handleItemChange() {
if (this.datalist.length === 0) {
this.isAllChecked = false
return
}
this.isAllChecked = this.checkList.length === this.datalist.length
}
}
}
createApp(obj).mount('#app')
</script>
</html>
6-3表单修饰符
.lazy
change事件 数据发生变化 并失去焦点触发
<!--在"change"事件后同步更新而不是"input"-->
<input v-model.lazy="msg" />
.number
用户输入自动转换为数字,你可以在v-model后添加.number修饰符来管理输入:
<input v-model.number="age" />
.trim
默认自动去除用户输入内容中两端的空格,你可以在v-model后添加.trim修饰符:
<input v-model.trim="msg" />
7.计算属性
7-1计算属性-很聪明,会缓存
模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。
<script>
const { createApp } = Vue
let obj = {
data() {
return {
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
},
computed: {
publishedBooksMessage() {
return this.books.length > 0 ? 'Yes' : 'No'
}
}
}
createApp(obj).mount('#app')
</script>
若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
7-2 可写计算属性
计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建:
<script>
const { createApp } = Vue
let obj = {
data() {
return {
"myname": "kerwin",
"year": 2023,
"month": 12,
"day": 31
}
},
computed: {
compuntedDate: {
get() {
return this.year + "-" + this.month + "-" + this.day
},
set(value) {
// console.log(value.split("-"))
// this.year = value.split("-")[0]
// this.month = value.split("-")[1]
// this.day = value.split("-")[2]
[this.year, this.month, this.day] = value.split("-")
}
},
}
}
let app = createApp(obj).mount('#app')
</script>
7-3之前案例的小改造
computed:{
isAllChecked:{
get(){
return this.checkList.length ===this.datalist.length
},
set(checked){
// console.log(value)
this.checkList = checked?this.datalist:[]
}
},
注意:
(1)Getter不应有副作用
计算属性的getter应只做计算而没有任何其他的副作用,这一点非常重要,请务必牢记。举例来说,不要在getter中做异步请求或者更改DOM!
(2)避免直接修改计算属性值
从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。
7-4侦听器watch的对比
watch选项期望接受一个对象,其中键是需要侦听的响应式组件实例属性(例如,通过data或computed声明的属性)——值是相应的回调函数。该回调函数接受被侦听源的新值和旧值。
computed&& watch
计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。
fetch函数返回一个Promise对象,可以使用.then()
方法来处理成功的响应,使用.catch()
方法来处理错误。在成功的响应处理函数中,可以通过response.json()
方法获取响应体的JSON数据。
<body>
<div id="app">
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</div>
</body>
<script>
const { createApp } = Vue
let obj = {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)'
}
},
watch: {
// 每当 question 改变时,这个函数就会执行
question(newQuestion, oldQuestion) {
if (newQuestion.includes('?')) {
this.getAnswer()
}
}
},
methods: {
async getAnswer() {
this.answer = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
console.log(res);
this.answer = await (res.json()).answer
} catch (error) {
this.answer = 'Error! Could not reach the API. ' + error
}
}
}
}
createApp(obj).mount('#app')
</script>
7-5深层侦听器
watch
默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数——而嵌套属性的变化不会触发。如果想侦听所有嵌套的变更,你需要深层侦听器:
watch
默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。
我们可以用一个对象来声明侦听器,这个对象有 handler
方法和 immediate: true
选项,这样便能强制回调函数立即执行:
<body>
<div id="box">
<input type="text" v-model="mytext">
<select v-model="obj.year">
<option value="2021">2021</option>
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
</select>
<select v-model="obj.month">
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
<select v-model="obj.day">
<option value="31">31</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<script>
var obj = {
data() {
return {
mytext: "",
obj: {
year: 2023,
month: 12,
day: 31
}
}
},
watch: {
// mytext:function(){}
mytext: "anyfunc",
// "obj.year":"anyfunc",
// "obj.month":"anyfunc",
// "obj.day":"anyfunc"
obj: {
handler(value) {
console.log(value, "ajax")
},
deep: true,//复杂对象进行深度监听
immediate: true
}
},
methods: {
anyfunc(value, oldvalue) {
console.log(value)
}
}
}
Vue.createApp(obj).mount("#box")
</script>
</body>
8.数据请求
8-1Fetch
XMLHttpRequest是一个设计粗糙的API,配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好。兼容性不好
https://github.com/camsong/fetch-ie8
fetch函数返回一个Promise对象,可以使用
.then()
方法来处理成功的响应,使用.catch()
方法来处理错误。在成功的响应处理函数中,可以通过response.json()
方法获取响应体的JSON数据。
response.text()方法获取相应主体文本形式
<div id="box">
<button @click="handleClick">click</button>
<ul>
<li v-for="item in datalist">
{{item.name}}-{{item.age}}
</li>
</ul>
</div>
<script>
var obj = {
data() {
return {
datalist:[]
}
},
methods:{
handleClick(){
//基于promise
// fetch("http://localhost:3000/list")
// .then(res=>res.json() )
// .then(res=>{
// console.log(res)
// this.datalist = res
// })
// fetch("http://localhost:3000/list",{
// method:"post",//post ,POST
// headers:{
// "content-type":"application/x-www-form-urlencoded",
// },
// body:"name=xiaoming&age=19"
// }).then(res=>res.json())
// .then(res=>{
// console.log(res)
// })
// fetch("http://localhost:3000/list",{
// method:"post",//post ,POST
// headers:{
// "content-type":"application/json",
// },
// body:JSON.stringify({
// name:"gandaner",
// age:20
// })
// }).then(res=>res.json())
// .then(res=>{
// console.log(res)
// })
// fetch("http://localhost:3000/list/5",{
// method:"put",//post ,POST
// headers:{
// "content-type":"application/json",
// },
// body:JSON.stringify({
// name:"gandaner1111",
// age:200
// })
// }).then(res=>res.json())
// .then(res=>{
// console.log(res)
// })
fetch("http://localhost:3000/list/5",{
method:"delete",//post ,POST
}).then(res=>res.json())
.then(res=>{
console.log(res)
})
}
}
}
var app = Vue.createApp(obj).mount("#box")
</script>
8-2 axios
Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中。
axios - npm
<body>
<div id="box">
<button @click="handleClick">click</button>
<ul>
<li v-for="item in datalist">
{{item.name}}-{{item.age}}
</li>
</ul>
</div>
<script>
var obj = {
data() {
return {
datalist:[]
}
},
methods:{
handleClick(){
// console.log(axios)
//get
// axios.get("http://localhost:3000/list").then(res=>{
// console.log(res.data)
// this.datalist = res.data
// }).catch(err=>{
// console.log(err)
// })
//post-json
// axios.post("http://localhost:3000/list",{
// name:"gangdaner",
// age:20
// }).then(res=>{
// console.log(res.data)
// }).catch(err=>{
// console.log(err)
// })
//post-form
// axios.post("http://localhost:3000/list","name=zhugeshanzhen&age=30").then(res=>{
// console.log(res.data)
// }).catch(err=>{
// console.log(err)
// })
//put
// axios.put("http://localhost:3000/list/6","name=zhugeshanzhen111&age=300").then(res=>{
// console.log(res.data)
// }).catch(err=>{
// console.log(err)
// })
//delete
// axios.delete("http://localhost:3000/list/6").then(res=>{
// console.log(res.data)
// }).catch(err=>{
// console.log(err)
// })
axios({
// header:{
// }
method:"delete",
url:"http://localhost:3000/list/5",
// data:{
// "name": "gangdaner111",
// "age": 200,
// }
}).then(res=>{
console.log(res)
})
}
}
}
var app = Vue.createApp(obj).mount("#box")
</script>
</body>
9.过滤器
9-1vue3过滤器不支持了-怎么办?
在2.x中,开发者可以使用过滤器来处理通用文本格式。
<body>
<div id="box">
<!-- {{myname}} -->
{{mydate | mydatefilter}}
</div>
<script>
var obj = {
el:"#box", //element
data() {
return {
myname:"kerwin",
mydate:1679458576574
}
},
filters:{
mydatefilter(timestamp){
// console.log(timestamp)
var mydate = new Date(timestamp)
return mydate.getFullYear()+"-"+(mydate.getMonth()+1)
}
}
}
// var app = Vue.createApp(obj)
// .mount("#box")
new Vue(obj)
</script>
</body>
虽然这看起来很方便,但它需要一个自定义语法,打破了大括号内的表达式“只是JavaScript”的假设,这不仅有学习成本,而且有实现成本。在3.x中,过滤器已移除,且不再支持。取而代之的是,我们建议用方法调用或计算属性来替换它们。
<body>
<div id="box">
{{mydatefilter(mydate)}}
</div>
<script>
var obj = {
data() {
return {
mydate: 1679458576574
}
},
methods: {
mydatefilter(timestamp) {
// console.log(timestamp)
var mydate = new Date(timestamp)
return mydate.getFullYear() + "-" + (mydate.getMonth() + 1)
}
}
}
var app = Vue.createApp(obj)
.mount("#box")
</script>
</body>