Vue全系列
参考
2021版-vue3.0+vue全家桶全系列精讲(多案例+多项目)【撩课】
vue 官网
基础语法
mustache语法
{{ 可以写简单的表达式,不能是语句 }} 只能用于开始标签与结束标签中间,不能用于标签中
<div id="app">
<h1>{{ msg }},love baby</h1>
<h1>{{ msg + '' + site}}</h1>
<h1>{{ msg }} {{site}}</h1>
<h1>{{ count*2 / 10 }}</h1>
</div>
v-once:只会变化一次
<div id="app">
<h1>会变化:{{ msg }}</h1>
<h1 v-once>不会变化:{{ msg }}</h1>
</div>
v-text:插值表达式mustache的效果
v-text会把innerTEXT中的内容覆盖,{{}}不会覆盖
<div id="app">
<h1>{{ msg }}内容不被覆盖</h1>
<h1 v-text='msg'>内容被覆盖</h1>
</div>
v-html:注入带html格式的内容
业务型功能有注入风险,不使用v-html
<div id="app">
<div>{{ web }}解析为文本</div>
<br>
<div v-html='web'>解析为html标签</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg: '我爱宝贝',
web: '<a href="http://www.baidu.com/">百度</a>'
},
methods: {
}
})
</script>
v-pre:不编译,所见即所得
<div id="app">
<h1 v-pre>不产生编译:{{ msg }}</h1>
<br>
<h1>正常双向绑定:{{ msg }}</h1>
</div>
v-cloak:避免页面加载慢,页面展示出mustache语法
vue实例解析之前,h1标签有v-cloak属性
vue实例解析之后,h1标签没有了v-cloak属性
<style type="text/css">
[v-cloak]{
display: none;
}
</style>
<div id="app">
<h1 v-cloak>{{ msg }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
setTimeout(()=>{
var app = new Vue({
el: '#app',
data: {
msg: '我爱宝贝',
web: '<a href="http://www.baidu.com/">百度</a>'
},
methods: {
}
})
},1000)
</script>
v-bind:动态绑定src等属性
属性可变时,v-bind动态绑定标签属性和vue对象中数据
v-bind:src 可以写为 :src
<div id="app">
<!-- <img src="imgUrl" > imgUrl会被解析为普通字符串-->
<img v-bind:src="imgUrl" v-bind:alt="alt">
<a :href="site">撩课学院</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg:'我爱宝贝',
imgUrl:'https://i0.hdslb.com/bfs/face/ca4767f400f735032a9a8053db730476ea94e27d.jpg@96w_96h_1c_1s.webp',
alt:'撩课学院',
site:'http://www.baidu.com'
},
methods: {
}
})
</script>
模板界面中,很多元素的样式是变化的,class/style用于动态绑定类和样式
<style type="text/css">
.red {
color: red;
}
.f60 {
font-size: 60px;
}
</style>
<div id="app">
<h1 class="red">{{ msg }}</h1>
<h1 :class="red">{{ msg }}</h1>
<!--动态绑定样式-->
<!--多个样式-->
<!-- <p :class="{类名1:布尔值,类名2:布尔值}">{{ msg }}</p> -->
<p class="box" :class="{red:true,f60:true}">{{ msg }}</p> <!--动态绑定样式和固定样式可以并存,不会相互覆盖-->
<p class="box" :class="{red:isRed,f60:isF60}">{{ msg }}</p>
<button type="button" @click="change">切换</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg: '我爱宝贝',
red: 'red',
f60: 'f60',
isRed: true,
isF60: true
},
methods: {
change(){
this.isRed = !this.isRed,
this.isF60 = !this.isF60
}
}
})
</script>
使用数组动态绑定样式
<h1 class="red f60">{{ msg }}</h1>
<!--用数组的方式动态绑定样式-->
<h1 :class="[red,f60]">{{ msg }}</h1>
<!--样式多的时候,封装到一个函数-->
<!--使用事件调用函数时不写小括号,其他时候调用函数时要写小括号-->
<h1 :class="getClass()">{{ msg }}</h1>
<script>
var app = new Vue({
el: '#app',
data: {
msg: '我爱宝贝',
red: 'red',
f60: 'f60',
},
methods: {
getClass(){
return [this.red,this.f60];
}
}
})
</script>
动态绑定style样式,以键值对数组的方式绑定多个可变样式,样式长可以抽出为一个函数
style=" 之间的内容是以 css 的形式解析的"
v-bind:style=" 之间的内容是以 js 的形式解析的"
font-size 对应 fontSize
<div id="app">
<p style="font-size: 50px;">{{ msg }}</p>
<p :style="{fontSize: '50px'}">{{ msg }}</p>
<!-- 以键值对数组的方式绑定多个样式 -->
<p :style="{fontSize: f50,backgroundColor:red}">{{ msg }}</p>
<!-- 样式多的时候抽出为一个函数 -->
<p :style="getStyle()">{{ msg }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg: '我爱宝贝',
red: 'red',
f50: '50px',
}, <!-- 注意这里的逗号,没有逗号报错 -->
methods: {
getStyle(){
return {fontSize: this.f50,backgroundColor:this.red};
}
}
})
</script>
v-on:监听事件
v-on:click 可以简写为 @click
<div id="app">
<p>运算结果:{{count }}</p>
<button v-on:click="sub()">-</button> <!-- 不用传参可以去掉小括号,仅限于事件调用函数,其他情况调用函数括号都不能去掉 -->
<button @click="add">+</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
sub(){
this.count--;
},
add(){
this.count++;
}
}
})
</script>
绑定事件的参数传递
<div id="app">
<!--不带参数-->
<button type="button" @click="btn1()">有括号不传参</button>
<button type="button" @click="btn2">没括号</button>
<button type="button" @click="btn3(123,'a',true,msg)">有参数</button> <!--msg会在vue对象中找-->
<!--事件对象参数用$event-->
<button type="button" @click="btn4(123,'a',true,msg,$event)">事件对象参数</button> <!--msg会在vue对象中找-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg:'我爱宝贝'
},
methods: {
btn1(args){
console.log(args); <!--undefined-->
},
btn2(args){
console.log(args); <!--输出click事件对象-->
},
btn3(arg1,arg2,arg3,arg4){
console.log(arg1,arg2,arg3,arg4); <!--输出所有参数-->
// console.log(Arguments); <!--输出所有参数-->
},
btn4(arg1,arg2,arg3,arg4,arg5){
console.log(arg1,arg2,arg3,arg4,arg5); <!--输出所有参数-->
}
}
})
</script>
v-on 常用修饰符
下面第一张图点击了button按钮,div关联的事件也触发了,称为冒泡
第二张图点击button,div关联事件不触发,阻止了冒泡
<div id="app">
<!--阻止冒泡:点击div内部按钮时,不会冒泡到div相关的事件-->
<div class="box" @click="boxClick">
<button type="button" @click.stop="btnClick">按钮</button>
</div>
<!--阻止默认事件:阻止表单提交,不阻止的话,点击submit表单会直接提交到action-->
<form action="http://www.baidu.com/">
<input type="submit" value="提交" @click.prevent="doSubmit"/>
</form>
<a href="http://www.baidu.com" @click.prevent="doSubmit">百度</a>
<!--响应一次事件-->
<button type="button" @click.once="btnClick">只有第一次点击生效</button>
<!--键盘事件修饰符:获取用户按键信息 .keycode .enter .tab .delete .esc .space .up .down .left .right-->
<input type="text" @keyup="getMsg" />
<input type="text" @keyup.enter="getMsg" /> <!--回车时事件才响应-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
},
methods: {
boxClick(){
console.log("点击了盒子")
},
btnClick(event){
// event.stopPropagation(); <!--阻止冒泡原始写法-->
console.log("点击了按钮")
},
doSubmit(event){
// event.preventDefault(); 阻止默认事件
console.log("表单提交")
},
getMsg(event){
console.log(event);
},
}
})
</script>
计算属性:数据需要简单的处理再显示
- 页面中某个展示需要经过多个属性共同运算得到,多个属性共同运算的逻辑放到计算属性中
- 内部实现: computed{ fullName(){ 计算属性内部其实有set和get方法,更改取值用的其实是set和get }}
- 函数和计算属性的区别:页面中多次使用同一计算属性时,第一个计算属性加载完毕后,会缓存起来,再加载同样的计算属性时,检查计算属性中的值是否没发生变化,如果没有发生变化就不会再运算,直接用缓存,而函数每次调用都会再次计算
<div id="app">
<p>宝贝·老婆</p>
<!--常规写法,不应该在这里写太多的逻辑代码,容易与vue对象产生耦合-->
<p>{{ firstName + '·' + lastName}}</p>
<!--函数-->
<p>{{ getFullName() }}</p> <!--除事件调用函数之外不能省略小括号-->
<!--计算属性-->d
<p>{{ fullName }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
firstName:'宝贝',
lastName:'老婆',
},
// 计算属性
computed:{
// 本质上还是属性,写法如函数,命名如属性
fullName(){
return this.firstName + '·' + this.lastName;
}
},
methods: {
getFullName(){
return this.firstName + '·' + this.lastName;
}
}
})
</script>
计算属性处理数组,用到 for(let member of this.members){} 循环for
<div id="app">
<p>{{ members[0].score + members[1].score + members[2].score}}</p>
<!--使用计算属性-->
<p>{{ totalScore }}</p> <!--计算属性本质是一个属性,不能写totalScore() -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
members:[
{name:'张三',score:89},
{name:'李四',score:92},
{name:'王五',score:91}
]
},
computed:{
totalScore(){
let total = 0;
for(let member of this.members){
total += member.score;
}
return total;
}
},
<!--vue对象中只要有语法错误,mustache就会直接显示{{}}原始格式-->
methods: {
}
})
</script>
v-if和v-show
- v-if 是真正的条件渲染,实现原理是组件的销毁和创建
- v-show不管初始条件是什么,元素都会被渲染,只会被创建一次,显示和隐藏是基于css display:none 实现
- 经常切换用v-show,否则用v-if
<div id="app">
<div v-if="flag">和宝贝去深圳</div>
<div v-else="flag">和宝贝去北京</div>
<p>===============</p>
<div v-show="flag">和宝贝去北京</div>
<div v-show="!flag">和宝贝去天津</div>
<br>
<button type="button" @click="flag=!flag">切换</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
flag:true
},
methods: {
}
})
</script>
v-if和v-show切换登录方式
- v-if切换登录方式,会把原来输入的内容清空,因为原理是div的销毁和创建
- v-show切换登录方式,会记录上一次填入的内容
<div id="app">
<!-- v-if切换登录方式,会把原来输入的内容清空,因为原理是div的销毁和创建 -->
<!-- <div v-if="loginType==='phone'"> === 三个等号表示恒等于,类型相同值相同
手机:<input type="text" placeholder="请输入手机号码"/><br>
密码:<input type="password" placeholder="请输入密码"/><br>
</div>
<div v-else>
邮箱:<input type="text" placeholder="请输入邮箱"/><br>
密码:<input type="password" placeholder="请输入密码"/><br>
</div> -->
<!-- v-show切换登录方式,会记录上一次填入的内容 -->
<div v-show="loginType ==='phone'">
手机:<input type="text" placeholder="请输入手机号码"/><br>
密码:<input type="password" placeholder="请输入密码"/><br>
</div>
<div v-show="loginType === 'email'">
邮箱:<input type="text" placeholder="请输入邮箱"/><br>
密码:<input type="password" placeholder="请输入密码"/><br>
</div>
<button @click="change">切换登录方式</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
loginType:'phone'
},
methods: {
change(){
this.loginType === 'phone' ? this.loginType = 'email' : this.loginType = 'phone'
}
}
})
</script>
v-for:数据遍历
v-for=“e in elements” 或者v-for=“(e,index) in elements”
v-if 的优先级大于 v-for,一般不要在同一个标签中,同时使用两者
<div id="app">
<ul>
<li v-for="e in aicheng">{{ e }}</li>
</ul>
<ul>
<li v-for="(e,index) in aicheng">{{ index }}:{{ e }}</li>
</ul>
<ul>
<li v-for="e in date">{{ e.begin }}-{{ e.location }}-{{ e.love }}</li>
</ul>
<ul>
<li v-for="item in baby">{{ item }}</li> <!--得到的是value-->
<p>===============</p>
<li v-for="(item,key) in baby">{{ key }}:{{ item }}</li>
<p>===============</p>
<li v-for="(item,key,index) in baby">{{ index }}-{{ key }}:{{ item }}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
//数组
aicheng:['宝贝','老婆','宝儿','媳妇儿'],
//json数组
date:[
{begin:'1.5',location:'邯郸',love:'爱你'},
{begin:'4.22',location:'武汉',love:'永远爱你'},
{begin:'7.2',location:'济南',love:'这辈子就是你了'},
],
//对象
baby:{
name:'宝贝',
age:18,
love:'我可爱的女朋友',
}
})
</script>
计算属性实现排序和条件搜索
<head>
<meta charset="utf-8">
<title>Vue基础</title>
<style type="text/css">
ul li{
list-style: none;
line-height: 40px;
}
body{
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<h3>搜索</h3>
<label><input type="text" placeholder="请输入关键词" v-model="searchStr"/></label>
<h3>排序</h3>
<button type="button" @click="setOrderType(2)">年龄升序</button>
<button type="button" @click="setOrderType(1)">年龄降序</button>
<button type="button" @click="setOrderType(0)">还原</button>
<div>
<ul>
<li v-for="(p,index) in filterPerson">{{ index + 1 }}-{{ p.name }}-{{ p.age }}</li>
</ul>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
person:[
{name:'张三',age:'19'},
{name:'王五',age:'22'},
{name:'张六',age:'20'}
],
//管理输入框
searchStr:'',
//flag 默认0,升序1,降序2
orderType:0
},
//计算属性,得到筛选后的展示数组
computed:{
filterPerson(){
//1.取出相关属性
const{person,searchStr,orderType} = this;
//2.定义过滤数组
let arr = [...person]; //深拷贝
//3.根据条件过滤
if(searchStr.trim()){
arr = person.filter((p)=>{
return p.name.indexOf(searchStr) != -1;
})
}
//4.排序
if(orderType){
arr.sort((p1,p2)=>{ //sort底层是冒泡排序
//升序
if(orderType === 2){
return p1.age - p2.age; //表示从p1到p2升序
//降序
}else{
return p2.age - p1.age;
}
})
}
//5.返回过滤后的数组
return arr;
}
},
methods:{
setOrderType(orderType){
this.orderType = orderType;
}
}
})
</script>
</body>
v-model
v-model绑定的元素值和输入框同步
<div id="app">
<!-- <input type="text" :value="msg" @input="valueChange"/> -->
<input type="text" :value="msg" @input="msg=$event.target.value"/>
<h1>{{ msg }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
msg:'我爱宝贝'
},
methods:{
valueChange(event){
console.log("---------------")
this.msg = event.target.value;
}
}
})
</script>
v-model 结合单选
<div id="app">
<label><input name="sex" type="radio" value="男" v-model="sex"/>男</label>
<label><input name="sex" type="radio" value="女" v-model="sex"/>女</label>
<p>==========</p>
<h2>选择的性别是:{{ sex }}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
sex:''
}
})
</script>
v-model 结合多选
<div id="app">
<!-- 单个选项 -->
<label>
<input type="checkbox" v-model="isAgree"/>同意永远爱宝贝协议
</label>
<h2>是否同意协议:{{ isAgree ? '同意' : '不同意' }}</h2>
<button type="button" :disabled="!isAgree">注册</button>
<p>=================</p>
<!-- 多个选项 -->
<label>兴趣爱好:</label>
<input type="checkbox" value="宝贝" v-model="hobbies"/>宝贝
<input type="checkbox" value="老婆" v-model="hobbies"/>老婆
<input type="checkbox" value="小韩" v-model="hobbies"/>小韩
<h2>用户兴趣爱好:{{ hobbies }}</h2>
<p>==================</p>
<!-- 值绑定 -->
<label v-for="like in likes" :for="like"> <!-- :for 关联ID-->
<!-- 循环的是like,绑定的是love ,选中什么,在love中存入什么 -->
<input type="checkbox" :value="like" :id="like" v-model="love"/>{{ like }}
</label>
<h2>用户兴趣爱好:{{ love }}</h2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
isAgree:'',
hobbies:[],
likes:["宝贝","老婆","小韩"],
love:[]
}
})
</script>
其他
列表删除增加等为什么要绑定key
为了给vue一个提示,方便它追踪每个节点的身份,从而重用和重新排序现有的元素,需要为每一项提供一个唯一的key
不要使用对象或者数组之类的非基本类型的值作为v-for的key,请使用字符串或数值类型的值
<div v-for="item in items" :key="item.id">
</div>
组件
略