插值语法(大胡子表达式)
{{ 初始化的值 }}{{ 初始化的值 }}
插值语法只能使用在标签外,不能使用在标签上
插值语法只支持单向绑定功能,可以进行非常简单的业务逻辑
无法实现 迭代 流程控制等,需要搭配指令语法进行更复杂的操作
<div id="app">
{{message}} //渐进式JavaScript框架
{{count/10}} //10
{{flag?'ios':'android'}} //ios
<!-- 插值语法无法显示 null 和 undefined 什么都不显示 -->
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:'#app',
data = {
/* 这被称之为初始化的值 */
message: '渐进式JavaScript框架',
count: 100,
flag: true,
text: '123.456.789',
val1: null,
val2: undefined,
value1: '<span style="color:coral">测试</span>',
mySrc: './assets/logo.png',
myCss: 'width:100px',
myStyle: 'background-color:rgb(255,0,255)',
myFlag: false,
}
})
</script>
指令语法
格式:
<tagName v-指令名="绑定的值" />
v-html:向元素中插入超文本,支持标签css等,就相当于js中 innerHTML
v-text:向元素中插入文本,不支持标签 css等,相当于js中的innerText
在前端开发时,为了避免XSS网络攻击,严禁插入 动作
<p v-html="value1" style="background-color: pink;"></p>//格式生效
<p v-text="value1" style="background-color: pink;"></p>//显示 <span style="color:coral">测试</span>
v-once:一次性插值绑定,仅仅实现了一次的单向绑定,之后失效
<div v-once>{{ message }}</div>
v-model:天生支持单双向绑定,只能使用在表单项中,类似之前的value属性值,但是绑定初始化的数据
v-model如果使用在复选框中
单向绑定:
如果data初始化的值为真值,则勾选
为假值则不勾选
双向绑定:
主动勾选,则绑定的值为true,主动不勾选
则为false
<input type="text" v-model="count" :style="myStyle">
<input type="checkbox" v-model="myFlag">
v-on:后面绑定事件,激发事件之后联动执行绑定的函数<tagName v-on:事件="函数" />
语法糖:使用 @ 取代 v-on 绑定事件<tagName @事件="函数" />
<button @click="count++">点我试试</button>
v-bind:绑定元素中属性,使之变为初始化的值,<tagName v-bind:属性名="初始化的值" />
语法糖:使用 :代替 v-bind,<tagName :属性名="初始化的值" />
<img :src="mySrc" :title="message":style="myCss">
Vue实例
即MVVM中的VM,通过Vue实例来显示单向和双向绑定
const vm = new Vue({
/* el:element的简写,用来选择管理的模板
这里表示Vue实例 vm 管理我们上面的div */
el:'#app',
/* data:初始化的数据 */
data:{
属性名:属性值
},
/* 设置函数(此处也可以称之为方法,因为如果函数放置在
对象中,则可以称之为方法) */
methods:{
函数名(){
},
},
})
函数 计算属性 侦听器
<div id="app">
//由于成绩是number类型,输入框中都是字符串类型,所以需要v-model.number转换为number类型
前端成绩: <input type="text" v-model.number="frontEndScore"> <br>
后端成绩: <input type="text" v-model.number="backEndScore"> <br>
<hr>
//注意由于这里的函数没有绑定事件,所以这里相当于调用函数,所以添加了括号
//函数只能实现单向绑定
总成绩(函数-单向绑定): <input type="text" v-model="sumScore()"> <br>
//此处使用计算属性 注意计算属性永远不会使用括号,它就是一个属性,不会传值
//计算属性既可以单向绑定又可以双向绑定
总成绩(计算属性-单向绑定): <input type="text" v-model="totalScore"> <br>
//v-model.lazy="" 开启延迟双向绑定,当用户点击回车时才开启双向绑定功能,如果不开启会导致用户一边输入,一边进行绑定计算
总成绩(计算属性-单双向绑定): <input type="text" v-model.number.lazy="totalScores"> <br>
//侦听器 同样可以单双向绑定,有几个参数设置几个侦听器
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
frontEndScore:100,
backEndScore:80,
totalWatch:0,
},
//设置函数
methods:{
sumScore(){
return this.frontEndScore + this.backEndScore
},
},
//设置计算属性
computed:{
//单向绑定
totalScore(){
return this.frontEndScore + this.backEndScore
},
//单双向绑定完全版
totalScores:{
//单向绑定
get(){
return this.frontEndScore + this.backEndScore
},
//双向绑定 val是形参,就是主动填入的总成绩
set(val){
let avgScore = val/2
this.backEndScore = avgScore
this.frontEndScore = avgScore
},
},
},
//设置侦听器
watch:{
//设置要侦听的值
frontEndScore:{
//立即执行一次侦听器 刚打开页面显示的值
immediate:true,
//newVal:形参,被侦听的数据更改后的值
//oldVal:形参,被侦听的数据更改后的值
handler(newVal,oldVal){
//总成绩=新的前端成绩 + 后端成绩
this.totalWatch = newVal + this.backEndScore
},
//实现双向绑定的话要同时侦听这三个属性 代码同上
},
},
})
//在Vue实例外调用侦听器
vm.$watch('backEndScore',{
immediate:true,
handler(newVal,oldVal){
this.totalWatch = newVal + this.frontEndScore
}
})
</script>
条件渲染
.test{
width:100px;
height:100px;
background-color: pink;
}
<div id="app">
//v-model 不能取反
隐藏元素: <input type="checkbox" v-model="flag1"> //一个复选框 flag1为true勾选
<br>
//v-if:后面如果绑定真值,元素显示,底层渲染,否则元素隐藏,底层不渲染,可以取反
//v-if切换消耗较大,适用于切换不频繁的场合
<div class="test" v-if="!flag1">测试</div>
隐藏元素: <input type="checkbox" v-model="flag2">
<br>
//v-show:后面如果绑定一个真值,元素显示,底层渲染,否则元素隐藏,底层依然渲染,可以取反
//元素隐藏只不过是在元素上添加了一个display:none 行内式
//适用于切换频繁的场合,仅仅初始载入消耗较大
<div class="test" v-show="!flag2">测试</div>
//Vue2.4新特性 v-else-if v-else 以上两个必须搭配v-if使用
<button @click="count++">点我试试!</button>
//template标签,Vue提供得用来设置指令的标签最终浏览器并不会解析此标签,也不会作用于真实DOM中 以下三个指令必须紧邻
<template v-if="count===1">React世界排名第一</template>
<template v-else-if="count===2">Vue紧随其后</template>
<template v-else>jQuery濒临淘汰</template>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
flag1:false,
flag2:false,
count:0,
},
})
</script>
样式渲染
所谓样式渲染就是指使用Vue来灵活的控制页面中的样式 主要有以下两个思路
1: v-bind绑定class
:class="初始化的值"
初始化的值对应类名
(频繁使用!) :class="{类名1:初始化的值,类名2:初始化的值}"
如果初始化的值为真,则类名存在,为假,则类名不存在
class后面是数组: :class="['类名1','类名2']"
2: v-bind绑定style
:style="初始化的值"
初始化的值对应样式
:style="{样式名:初始化的值,样式名:初始化的值,}" 样式名必须使用小驼峰格式
<p :class="test1">绑定class,class后面是一个字符串</p>
<p :class="{box2:flag2,box3:flag3}">绑定class,class后面是一个对象</p>
<p :class="['box4','box5']">绑定class,class后面是一个数组</p>
<p :style="{backgroundColor:val1,color:val2}">绑定style,style后面是一个对象</p>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
test1:'box1',
flag2:null,
flag3:99,
val1:'tomato',
val2:'white',
},
})
</script>
列表渲染
//v-for:用来进行迭代,这个指定书写在哪个元素上,则这个元素会进行迭代
//1: 迭代数组
v-for = "(alias,index) in 循环体"
alias:别名
index:索引,不是必须,如果不写小括号可以省略
in:可以替换为of
:key:绑定id值,而不是使用默认的索引,否则可能会出现使用 unshift时输入bug
<table border="1px">
<tr>
<th>序号</th>
<th>姓名</th>
<th>性别</th>
<th>住址</th>
<th>操作</th>
</tr>
<tr v-for="(person,index) in persons" :key="person.id">
<td>{{ index+1 }}</td>
<td>{{ person.name }}</td>
<td>{{ person.gender === 0?'女':'男' }}</td>
<td>{{ person.location }}</td>
<td><span style="cursor: pointer;"
@click="del(index)">删除</span></td>
</tr>
</table>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
const persons=[]
new Vue({
el:'#app',
data:{
/* persons:persons, */
persons,
hero,
},
methods: {
del(index){
if(confirm('您确定删除本条记录吗?')){
this.persons.splice(index,1)
}
},
},
})
</script>
事件修饰符与事件原型
常见的事件修饰符
事件修饰符就是对事件的补充 @事件.事件修饰符="函数"
-
@事件.stop="函数" 屏蔽事件传播
<div @click="todo"> <button @click.stop="dothis">屏蔽事件冒泡(事件传播)</button> </div> //只会执行dothis不会执行todo -
@事件.prevent="函数" 屏蔽元素固有的一些动作 例如 链接提交 表单提交
<form action="./1-初识mvvm.html" @submit.prevent="sub"> <input type="submit" value="提交"> </form> <a href="./1-初识mvvm.html" @click.prevent="go">链接提交</a> -
@事件.once="函数" 只执行一次
<button @click.once="count++">{{ count }}</button> -
@keyup.键位名="函数" 当某个键位激发时执行后面的函数 @keydown.tab 注意tab键必须使用键盘键位落下
<input type="text" placeholder="请点击w" @keyup.w="w"> <input type="text" placeholder="请点击space" @keyup.space="space"> <input type="text" placeholder="请点击enter" @keyup.enter="enter" >
事件原型
//如果函数没有参数,则底层自动给我们传递一个事件原型,就表示这个激发的事件
<button @click="touch1">点我试试!</button>
//如果函数存在实参,则不再默认底层传递事件原型了,如果我们还想使用,则需要自己传递实参 $event
<button @click="touch2('hello',$event)">点我试试!</button>
new Vue({
el:'#app',
data:{
content:'<em style="color:red">初始化的数据</em>',
},
methods:{
//event:形参 表示自动传递的事件原型
touch1(event){
//event.target表示这次事件激发的目标 这里就是button元素节点
let nodeBtn = event.target
nodeBtn.innerHTML = this.content
},
touch2(val,event){
event.target.innerText = val
}
},
})
表单双向绑定
//v-model.trim 去掉双向绑定的字符串两侧空格
用户姓名: <input type="text" v-model.trim="myForm.vname"> <br>
用户密码: <input type="password" v-model.trim="myForm.vpass"> <br>
// 此处value属性为事先写好,只要与
//v-model双向绑定的值对应,则默认选中,与真假值无关
性别: <input type="radio" name="gender" value="00000" v-model="myForm.vgender">女
<input type="radio" name="gender" value="11111" v-model="myForm.vgender">男 <br>
// 注意此处依然对应value属性值,由于可以操作多个数据
//所以这里是一个数组
爱好: <input type="checkbox" name="hobby" value="soccer" v-model="myForm.vhobby">足球
<input type="checkbox" name="hobby" value="running" v-model="myForm.vhobby">跑步
<input type="checkbox" name="hobby" value="shopping" v-model="myForm.vhobby">购物
<input type="checkbox" name="hobby" value="travel" v-model="myForm.vhobby">旅行
<input type="checkbox" name="hobby" value="game" v-model="myForm.vhobby">游戏 <br>
//注意这里最终双向绑定的v-model是书写在select标签内
出差所在地:
<select name="location"
v-model="myForm.vlocation">
<option :value="city.id"
v-for="city in citys"
:key="city.id">{{ city.name }}</option>
</select>
<br>
<!-- 富文本框 -->
个人介绍:
<textarea name="info" cols="15" rows="3"
placeholder="请输入个人概况"
v-model.trim="myForm.vInfo"></textarea> <br>
<input type="submit" value="提交">
</form>
</div>
new Vue({
el: '#app',
data: {
/* 在封装数据时尽量将相同逻辑的数据封装在一个对象中
Vue3强烈推荐这种书写风格,切忌大量数据封装在data表层 */
myForm: {
vname: '',
vpass: '',
vgender: '',
/* 复选框对应数组 */
vhobby: [],
vlocation:'4',
vInfo:'',
},
citys: [
{ id: 1, name: '济南' },
{ id: 2, name: '青岛' },
{ id: 3, name: '杭州' },
{ id: 4, name: '上海' },
{ id: 5, name: '南京' },
{ id: 6, name: '昆山' },
{ id: 7, name: '深圳' }
]
},
methods: {
mySub(){
console.log('同步被屏蔽,异步要开始啦')
console.log(this.myForm)
}
},
})
过滤器
<div id="app">
<table border="1px">
<tr>
<th>id</th>
<th>姓名</th>
<th>支付方式</th>
</tr>
<tr v-for="user in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<!-- {{ 被过滤的值|过滤器名 }} -->
<td>{{ user.payType|myFilter }}</td>
</tr>
</table>
<!-- 注意不能与v-model连用 -->
<input type="text" :value="content|myFilter2">
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
const users = [
{ id: 1, name: 'elena', payType: 1, },
{ id: 2, name: 'nancy', payType: 2, },
{ id: 3, name: 'aleric', payType: 4, },
{ id: 4, name: 'tommy', payType: 3, },
{ id: 5, name: 'damon', payType: 3, },
{ id: 6, name: 'stefan', payType: 1, }
]
/* 数据字典(密码本) */
const payOptions = [
{ id: 1, type: '支付宝', },
{ id: 2, type: '微信', },
{ id: 3, type: '银行卡', },
{ id: 4, type: '现金', }
]
new Vue({
el: '#app',
data: {
users,
content:'中华台北剑道选手权因疫情取消!',
},
/* 设置过滤器 */
filters: {
/*
过滤器名(被过滤的值){
过滤器存在以下两个注意事项
1:过滤器不能使用this
2:过滤器不能与v-model连用
在表单中用 :value 替代
}
*/
myFilter(val) {
/*
const arr = [1,2,3,4]
let value = arr.find(a=>a>=3)
// 3
*/
const payObj = payOptions.find(
payOption => payOption.id === val)
return payObj?payObj.type:''
},
myFilter2(val){
if(!val){
return ''
}
return val.replace('中华台北','中国台湾省')
.replace('选手权','锦标赛')
}
},
})
</script>
自定义指令
-
1.全局自定义,全局的自定义指令一定书写在我们自己new的Vue实例之前
<div id="app1"> <p v-etoak="content"></p> </div> Vue.directive('etoak',{ //渲染样式 el:形参 表示书写指令的元素节点,这里el就是p元素节点 bind(el){ el.style.backgroundColor = 'coral' }, //渲染动作 el:同上 binding:就是这个元素 binding.value:就是这个指令元素绑定的值 inserted(el,binding){ el.innerHTML = binding.value.toUpperCase() } }) new Vue({ el:'#app', data:{ content:'thisisetoak', } }) -
2.局部自定义指令
<div id="app2"> <p v-etoak="content"></p> // 此处使用局部自定义创建一个 自定义指令用来 //实现自动获取焦点,取代兼容性几乎没有的 autofocus <input type="text" v-focus > </div> new Vue({ data:{ content:'loveu3000', }, directives:{ //设置指令名 focus:{ //渲染样式 bind(el){ }, //渲染动作 inserted(el,binding){ //强制激发获取焦点 el.focus() } } } }).$mount('#app2')
指令补遗
-
v-pre :提示Vue实例不编译此指令存在的元素
<h1 v-pre>{{ title }}</h1> //会直接显示大胡子表达式 不会展示里面的值 -
v-cloak :用来解决闪现问题
<style> /* 凡是存在此属性的元素 */ [v-cloak]{ /* 隐藏 */ display: none; } </style> //闪现问题:当真实DOM还未覆盖虚拟DOM时,会存在极短的时间被用户发觉,页面中显示插值语法,这对用户体验非常不友好,通过v-cloak可以解决此问题 //当虚拟DOM生成时,插值语法与指令语法无法被解析,所以直接作用于元素中,此处添加css隐藏元素,当真实DOM覆盖之后,指令元素已经被成功解析,元素上不再存在 v-cloak 所以此时css隐藏失效元素显示出来了 <p v-cloak>{{ title }}</p>
数据代理
一个对象可以对另一个对象属性进行操作,称之为数据代理
const person = {
name:'胡桃',
age:16,
}
//使用数据代理给对象添加属性
Object.defineProperty(person,'location',{
//添加属性值
value:'璃月',
//设置可枚举,默认false不可枚举 即获取所有属性名 console.log(Object.keys(person))无法展示 location
enumerable:true,
//设置可写,默认false不可写
writable:true,// 可以通过person.location = '地名' 进行修改
//设置可配置 默认false不可配置(删除)
configurable:true, //console.log(delete person.location)
})
//_data:源对象
//vm:代理对象
const _data = {
name:'胡桃',
age:16,
}
const vm = {
$demo1:'原生属性1',
}
//进行代理
Object.defineProperty(vm,'name',{
//读取vm的name属性执行此函数
get(){
console.log('name属性被读取,getter要执行了')
return _data.name
},
//修改vm的name属性执行此函数 newVal就是传入的新的name值
set(newVal){
console.log('name属性被修改,setter要执行了')
_data.name = newVal
}
})
Vue2实现对象和数组可响应式
<div id="app">
<ul>
<li v-if="person.name">姓名:{{ person.name }}</li>
<li>年龄:{{ person.age }}</li>
<li>住址:{{ person.location }}</li>
<li v-if="person.gender">性别:{{ person.gender }}</li>
<li v-for="hobby in person.hobbies">{{ hobby }}</li>
</ul>
<button @click="add">添加性别</button>
<button @click="del">删除姓名</button>
<button @click="add2">添加爱好</button>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
const vm = new Vue({
data:{
person:{
name:'胡桃',
age:16,
location:'璃月',
hobbies:['抽烟','喝酒','烫头'],
},
},
methods:{
add(){
//给对象person,添加gender属性,属性值为'女'
//this.person.gender = '女'
//上面的写法可以给对象添加属性,但是由于没有实现可响应式,没有添加getter和setter函数,页面模板不会出现变动
//以下写法 实现可响应式
this.$set(this.person,'gender','女')
//Vue.$set(this.person,'gender','女')
},
del(){
this.$delete(this.person,'name')
//Vue.$delete(this.name,'name')
},
add2(){
//以下写法 没有实现可响应式功能
//this.hobbies[3] = '敲代码'
/*
在Vue2中 对于数组实现可响应式与对象不同
必须使用以下 七个 封装过可响应式功能的
函数才可以实现可响应式
push()
unshift()
shift()
pop()
splice()
sort()
reverse()
这七个函数实现了可响应式功能,其它函数没有实现
这七个与js中的那七个不是一套,这是尤雨溪封装过以后的
加强版
*/
this.hobbies.push('敲代码')
},
},
}).$mount('#app')
</script>