文本差值:{{ }}
- 最基本的数据绑定形式是文本插值
{{ }},它使用的是“Mustache”语法 (即双大括号) - 在标签内部显示内容
- 【注】双大括号内只能写表达式
// 头部<head>引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<body>
<div id="box">
{{mytext}}
</div>
<script>
const obj = {
data(){
return {
mytext:"hello"
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
</body>
属性绑定: v-bind
- 只要是想要动态绑定的属性,就可以使用 v-bind:属性
- 可简写为 :属性
// 头部<head>引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<body>
<div id="box">
<img :src="url" alt="" :width="width">
----分割线----
<img v-bind="obj">
</div>
<script>
const obj = {
data() {
return {
url: "https://static.maizuo.com/pc/v5/usr/movie/abd301585b7661f088a0caaa0fb0c3b2.jpg?x-oss-process=image/quality,Q_70",
width: 200,
obj: {
src: "https://static.maizuo.com/pc/v5/usr/movie/abd301585b7661f088a0caaa0fb0c3b2.jpg?x-oss-process=image/quality,Q_70",
width: 200
},
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
</body>
双向绑定:v-model (表单绑定)
- 可以绑定表单元素的值
- 会根据表单元素的值自动更新 data 属性中的值
输入框
- v-model绑定的是value值
// 结构
<div id="box">
<input type="text" v-model="mytext">
<textarea v-model="mytext"></textarea>
<p>{{mytext}}</p>
</div>
// vue
<script>
const obj = {
data() {
return {
mytext: ""
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
多选框 - checkbox
- 在只有一个多选框的情况下:
- v-model绑定的是checked值(true和false)
- 有多个:
- v-model绑定的是数组,数组中是选中的checkbox的value值
- 【注】value值必须写,不然就没有意义了
<div id="box">
<!-- 单个多选框 -->
<p>
用户名:<input type="text" v-model="username">
</p>
<p>
记住用户名<input type="checkbox" v-model="isRem">
</p>
<p>用户名:{{username}}</p>
<p>是否记住密码:{{isRem}}</p>
<!-- 多个 -->
<p>
vue<input type="checkbox" value="vue" v-model="checkList">
react<input type="checkbox" value="react" v-model="checkList">
小程序<input type="checkbox" value="小程序" v-model="checkList">
</p>
<p>选中的多选框:{{checkList}}</p>
</div>
// vue
<script>
const obj = {
data() {
return {
username: "", // 用户名
isRem: false, // 默认不选中记住用户名
checkList: ["react"] // 默认选中value值为value的多选框
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
单选按钮
- v-model绑定同一个变量,就代表这几个单选按钮是一个组
- (有点像name值的绑定)
<div id="box">
<h2>radio -- 性别</h2>
<p>
男<input type="radio" value="男" v-model="sex">
女<input type="radio" value="女" v-model="sex">
</p>
<p>性别:{{sex}}</p>
</div>
// vue
<script>
const obj = {
data() {
return {
sex: "女" // 默认性别为女
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
下拉列表
- v-model绑定在select标签上,绑定的值就是selected(被选中的值),
- 值就是option的value值
<div id="box">
<h2>下拉列表</h2>
<select v-model="select">
<option :value="1">已发货</option>
<option :value="2">已取消</option>
<option :value="3">已完成</option>
<option :value="4">已付款</option>
</select>
<p>
选中的状态的值:{{select}}
</p>
</div>
// vue
<script>
const obj = {
data() {
return {
select:2 // 默认选中value值为2的option,也就是已取消
}
}
}
const app = Vue.createApp(obj).mount('#box')
</script>
表单修饰符
- 加在v-model后面
.lazy将input事件改为change事件,- change事件在失去焦点并且内容发生改变时触发
.number将输入的字符串转为数字- number修饰符在输入框中 type = number 时,会自动启用
.trim去除首尾空格
<!-- lazy -->
<input type="text" v-model.lazy="mytext">
{{mytext}}
<!-- trim -->
<input type="text" v-model.trim="mytext2">
{{mytext2}}
事件
事件处理器
- v-on:
- 简写:@
- 写法:
- v-on:事件名="方法名",简写为 @事件名="方法名"
- 没加小括号,也会执行方法,而且会自动传递一个事件对象 $event
- v-on:事件名="方法名(参数,$event)" 可简写
- $event是vue中内置的参数,表示事件对象
- 方法中只有一句代码,可以直接写在标签中,不用再去methods中定义方法 , 可简写
- v-on:事件名="方法名",简写为 @事件名="方法名"
<div id="box">
<!-- 写法 1 -->
<button @click="fn1">方法名不括号</button>
<!-- 写法 2 -->
<button @click="fn2($event,'cxm')">方法名加括号</button>
<!-- 写法 3 -->
<p>
<button @click="count--">减</button>
<span>{{count}}</span>
<button @click="count++">加</button>
</p>
</div>
<script>
const obj = {
data() {
return {
count: 0
}
},
methods: {
fn1(e) {
console.log("没加小括号,也会执行方法,而且会自动传递一个事件对象 $event", e);
},
fn2(e, name) {
console.log(name, e);
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
事件修饰符
- 可以链式调用
.stop:阻止事件冒泡.prevent:阻止默认事件.capture:使用事件捕获.self:只有事件发生在当前元素上才会触发.once:事件只触发一次.passive:事件只触发一次,并且事件会立即执行
<div id="box">
<h2>事件修饰符:</h2>
<!-- .self 点击当前元素才能触发 -->
<ul @click.self="clickUl">
<!-- .stop 阻止冒泡 -->
<li @click.stop="clickLi">1111</li>
<li>2222</li>
</ul>
<!-- .prevent阻止默认行为 -->
<form action="/login" @submit.prevent="submit">
<button type="submit">提交</button>
</form> <br>
<!-- .once 事件只触发一次 -->
<button @click=" isOnce && clickOnce()">抽奖(函数表达式)</button>
<button @click.once="clickOnce()">抽奖(事件修饰符)</button>
</div>
<script>
const obj = {
data() {
return {
isOnce: true,
}
},
methods: {
clickUl(e) {
console.log("ul --- click");
},
clickLi(e) {
console.log("li --- click");
// e.stopPropagation(); 阻止冒泡
},
submit(e) {
console.log("submit提交校验");
// e.preventDefault(); 阻止默认行为
},
clickOnce() {
console.log("抽奖只能触发一次哦~");
this.isOnce = false;
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
按键修饰符
- 可以链式调用
.enter:回车键触发事件.delete:删除键触发事件,包括backspace和delete.tab:tab键触发事件.esc:esc键触发事件.space:空格键触发事件.up:上键触发事件.down:下键触发事件.left:左键触发事件.right:右键触发事件.ctrl:ctrl键触发事件.alt:alt键触发事件.shift:shift键触发事件
<div id="box">
<!-- .enter 回车键触发事件 -->
<input type="text" v-model="mytext" @keyup.enter="mytext.trim() && add()" placeholder="按回车键提交数据">
<ul class="list">
<li v-for="(item,index) in list" :key="item">
<span>{{item}}</span>
<button @click=del(index)>删除</button>
</li>
</ul>
<!-- 链式调用 -->
<!-- 同时按下shift、ctrl、enter才可以触发 -->
<input type="text" @keyup.shift.enter.ctrl="myshow.trim() && addtArr()" v-model="myshow"
placeholder="按shift+ctrl+enter添加数组元素">
<p>{{arr}}</p>
</div>
<script>
const obj = {
data() {
return {
mytext: "",
list: ["aaaa", "bbbb"],
myshow: "",
arr: [11, 22]
}
},
methods: {
add() {
this.list.push(this.mytext)
this.mytext = ""
},
del(index) {
this.list.splice(index, 1)
},
addtArr() {
this.arr.push(this.myshow)
this.myshow = ""
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
小案例 - 模态框
// 结构
<div id="box">
<button @click.self="isShow=true">模态框</button>
<!-- 方式一: -->
<!-- <div id="overlay" v-show="isShow" @click.self="hide">
<div id="center">
<input v-model="mytext" /><br>
<button @click.stop="hide">login</button>
</div>
</div> -->
<!-- 方式二: -->
<div id="overlay" v-show="isShow" @click="hide">
<div id="center" @click.stop> <!-- 阻止事件冒泡 -->
<input v-model="mytext" />
<button @click.stop="hide">login</button>
</div>
</div>
</div>
// 行为
<script>
var obj = {
data() {
return {
isShow: false,
mytext: ""
}
},
methods: {
hide(e) {
this.isShow = false
this.mytext = ""
}
}
}
Vue.createApp(obj).mount("#box")
</script>
// 样式
<style>
#overlay {
background: rgba(0, 0, 0, 0.6);
width: 100%;
margin: auto;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#center {
background: #ffff;
border-radius: 5px;
/* 边框圆角 */
padding-top: 15px;
padding-left: 30px;
padding-bottom: 15px;
width: 290px;
height: 160px;
position: fixed;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
</style>
列表渲染:v-for
- 语法:v-for="(每一项,下标) in或of关键字 数组 "
- 【注】 v-if 和 v-for 不能在同一个标签中使用
- 可以在在外层中嵌套一个
template标签,在template中写v-for,在里层标签中写v-if - template标签不会生成节点在页面中,不会改变页面的结构
- 可以在在外层中嵌套一个
<body>
<div id="box">
<!-- 数组 -->
<ul>
<li v-for="(item,index) in arr">
{{item}} -- {{index}}
</li>
</ul>
<!-- 数组对象,解构 -->
<hr>
<ul>
<li v-for="({id,name},index) in arr1">
{{id}} ~ {{name}}
</li>
</ul>
<!--
of === in
在遍历对象的时候,内部会进行处理,把数组转为对象:Object.entries(obj)
-->
<hr>
<ul>
<li v-for="({id,name},index) of arr1">
{{id}} ~ {{name}}
</li>
</ul>
</div>
<script>
const obj = {
data() {
return {
arr: ["aaa", "bbb", "ccc", "ddd", "eee"],
arr1: [
{ id: 1003, name: "张三" },
{ id: 1004, name: "李四" },
{ id: 1005, name: "王五" },
]
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
</body>
:key值的设置
- 好处:可以提高性能
- key值设置后,vue内部会对key值进行一个缓存,如果key值没有变化,则不会更新dom节点
- 使用场景
- 一般与v-for搭配使用
- key值一般设置为不重复的id值,后端返回的数据中一般会有id值
- 虚拟dom:
- 虚拟dom是一个js对象,描述了真实dom结构
- 真实dom和虚拟dom的区别:
- 真实dom:浏览器渲染出来的页面
- 虚拟dom:js对象
<div id="box">
<ul>
<li v-for="({id,title,state},index) in datalist" :key="id">
{{title}}
</li>
</ul>
</div>
<script>
const obj = {
data() {
return {
datalist: [
{ id: 1001, title: "手机", state: 0 },
{ id: 1002, title: "衣服", state: 1 },
{ id: 1003, title: "裤子", state: 2 },
],
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
显示隐藏:v-show
- v-show="表达式"
- 为true时,显示元素;为false时,隐藏元素
- 操作的是元素的display属性
<div id="box">
<p v-show="show">我被显示了</p>
<p v-show="hide">我被隐藏了</p>
<p v-show="a===a">aaaaaa被显示了</p>
</div>
<script>
const obj = {
data() {
return {
show: true,
hide: false
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
条件渲染:v-if、v-else-if、v-else
- v-if
- v-else-if
- v-else
- v-if 和 v-show 的区别:
- v-show是操作元素的display属性,v-if是直接创建和删除元素
- 在频繁切换的时候,v-show会更好一些
<body>
<div id="box">
<!-- 用法1: -->
<ul>
<li v-for="({title,state},index) in datalist">
{{title}} --
<span v-if="state===0">未付款</span>
<span v-else-if="state===1">运输中</span>
<span v-else-if="state===2">已签收</span>
</li>
</ul>
<!--
用法2:
v-if 也可以判斷元素的显示和隐藏
v-if=" 表达式 "
v-if 判断为真,则创建,如果为假,则不创建
-->
<div v-if="show">我被显示了</div>
<div v-if="hide">我被隐藏了</div>
</div>
<script>
const obj = {
data() {
return {
datalist: [
{ title: "手机", state: 0 },
{ title: "衣服", state: 1 },
{ title: "裤子", state: 2 },
],
show: true,
hide: false
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
</body>
动态绑定class的方法
- 对象
- key: class名
- value: true/false
- true: 添加该class
- false: 不添加该class
- 数组
- 写入要添加的class名
// 样式
<style>
.color {color: orange;}
.bg {background: linen;}
.fs {font-size: 30px;line-height: 50px;}
</style>
// 标签
<div id="box">
<p :class="objClass">动态class的绑定方法 -- 对象</p>
<p :class="arr">动态class的绑定方法 -- 数组</p>
</div>
// vue
<script>
const obj = {
data() {
return {
// 对象
objClass: {
color: true,
bg: true,
fs: false
},
// 数组
arr: ["color", "fs"]
/*
在数组中添加新属性
vue2 不支持 后来添加新属性
vue3 支持
*/
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
动态绑定style的方法
- 对象
- key为样式名,value为样式的值
- 数组
- 数组中的每一项都会添加到标签上去
// 标签
<div id="box">
<p :style="styleObj">动态的添加style属性 -- 对象</p>
<p :style="styleArr">动态的添加style属性 -- 数组</p>
<button @click="add()">添加属性</button>
</div>
// vue
<script>
const obj = {
data() {
return {
// 对象
styleObj: {
color: "white",
backgroundColor: "red"
},
// 数组
styleArr: [
{ color: "white" },
{ backgroundColor: "orange", fontSize: "30px" }
]
}
},
methods: {
// 添加属性
add() {
this.styleObj.fontSize = "50px"
this.styleArr.push("text-align:center")
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
计算属性:Computed
- 调用方式:不用加括号,直接调用
- 好处:
- 计算属性可以用来简化模板{{ }}中的表达式
- 计算属性可以用来缓存数据,减少不必要的DOM操作
- 缓存的特性:是存储到内存中,当下次再次访问时,直接从内存中读取
- 【注】
- 计算属性是基于依赖的缓存,依赖改变,才会重新计算
- 计算属性中不能写异步操作
- 计算属性是可以被赋值的,通过get,set方法
简化表达式
<p>首字母大写:{{myName.toUpperCase().substring(0,1)+myNamesubstring(1).toLowerCase()}}</p>
<p>首字母大写:{{ComputedName}}</p>
data(){
return {
myNmae:"caoxinmei"
}
},
computed: {
// 首字母大写
ComputedName() {
console.log("计算属性被执行了!");
return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
},
}
缓存的特性
<div id="box">
<!-- 缓存的特性 ---与方法对比 -->
<p>
{{ComputedName}}
{{ComputedName}}
{{ComputedName}}
</p>
<p>
{{methodName()}}
{{methodName()}}
{{methodName()}}
</p>
</div>
<script>
const obj = {
data() {
return {
myName: "caoxinmei",
}
},
// 计算属性
computed: {
// 首字母大写
ComputedName() {
console.log("计算属性被执行了!");
return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
},
},
// 方法
methods: {
methodName() {
console.log("方法被执行了!");
return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
计算属性的赋值
<div id="box">
<!-- 计算属性的赋值 -->
<p>
{{ComputedDate}}
</p>
<!-- 在控制台输入 app.ComputedDate="2000-1-1" 可看到变化-->
</div>
<script>
const obj = {
data() {
return {
// 年月日
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
day: new Date().getDate(),
}
},
// 计算属性
computed: {
// 计算属性是可以被赋值的,get、set方法
ComputedDate: {
// 原理就是在设置的时候调用了set方法,改变了year、month、day的值
// get方法又依赖了year、month、day,所以当year、month、day改变时,就会触发get方法
get() {
return this.year + "年" + this.month + "月" + this.day + "日"
},
set(value) {
// 假设后端返回的数据格式为:2019-10-10
[this.year, this.month, this.day] = value.split("-")
}
}
},
}
const app = Vue.createApp(obj).mount("#box")
</script>
侦听器:watch
- 要监听那个数据,就在watch里面写一个相同名称的函数
- watch中可以写异步代码
- watch与conputed的区别:
- watch不会立即执行(除非加上 immediate:true),计算属性会立即执行
- watch监听一个状态,计算属性监听多个状态
- watch支持同步和异步,计算属性只支持同步
监听字符串
<div id="box">
<!-- 监听字符串,并通过异步实现 -->
<input type="text" v-model="mytext">
<ul>
<li v-for="item in list" :key="item">
{{item}}
</li>
</ul>
</div>
<script>
const obj = {
data() {
return {
// 模糊查询
mytext: "",
list: ["aaa", "bbb", "ccc", "abc", "aac", "aca", "bacc", "bbaa", "acac"],
copyList: ["aaa", "bbb", "ccc", "abc", "aac", "aca", "bacc", "bbaa", "acac"]
}
},
watch: {
// 监听mytext
mytext(value) {
// 模拟异步代码
setTimeout(() => {
this.list = this.copyList.filter(item => item.includes(value))
}, 1000)
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
监听对象
<div id="box">
<!-- 监听对象 -->
<!-- 场景:模拟查看对应日期的数据 -->
<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>
<p>{{obj}}</p>
</div>
<script>
const obj = {
data() {
return {
// 模拟对象
obj: {
year: 2023,
month: 12,
day: 31
}
}
},
watch: {
// 监听对象
// 方式一:监听对象中的某些属性,fn为回调函数
// "obj.year": "fn",
// "obj.month": "fn",
// "obj.day": "fn",
// 方式二:深度监听,监听对象中的所有属性,(不推荐)
obj: {
handler(value) {
console.log("深度监听" + value);
}, // 函数handler是固定写法
deep: true, // 深度监听
immediate: true // 立即执行
}
},
motheds: {
fn(value, oldvalue) {
console.log(value, oldvalue);
}
}
}
const app = Vue.createApp(obj).mount("#box")
</script>
fetch 和 axios 的使用
fetch
data() {
return {
datalist: []
}
},
methods: {
// 获取数据
get() {
fetch("./11.json")
.then(resp => resp.json())
.then(res => {
this.datalist = res.data.hot
console.log(res.data.hot);
})
}
}
axios
data() {
return {
datalist: []
}
},
methods: {
// 获取数据
get() {
axios.get("./12.json").then(res => {
console.log(res.data.data.films)
this.datalist = res.data.data.films
})
},
}