vue基本语法
插值操作
<-- Mustache语法 -->
<p>{{message}}</p>
<p>{{message*2}}</p>
<p>{{firstName}}{{lastName}}</p>
vue指令
v-once
该指令表示元素和组件只渲染一次,不会随着数据的改变而改变
<div id="app">
<h2 v-once>{{message}}</h2>
</div>
<script>
let vm= new Vue({
el:"#app",
data:{
message:"鸟飞"
}
})
</script>
v-html
将插值的内容(字符串)按照html标签来进行解析
<div id="app">
<h2>{{link}}</h2> <!-- 没有加v-once直接把link当作普通字符串来渲染 -->
<h2 v-html>{{link}}</h2> <!-- 将link渲染成一个a标签 -->
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
link:"<a href='http://www.baidu.com'>百度一下</a>"
}
})
</script>
v-text
和Mushtache比较,都用于进行数据显示
<div id="app">
<h2>{{message}}</h2>
<h2 v-text="message"></h2> <!-- 两种方式显示的效果一样 -->
</div>
<script>
let vm = new Vue({
el:"app",
data:{
message:"鸟飞"
}
})
</script>
v-pre
用于跳过这个元素和它子元素的编译过程,用于显示原本的Mushtache语法
<div id="app">
<h2>{{message}}</h2> <!-- 鸟飞 -->
<h2 v-pre>{{message}}</h2> <!-- {{message}} -->
</div>
<script>
let vm = new Vue({
data:{
message:"鸟飞"
}
})
</script>
v-cloak
应用场景:用于在VUE还没有实例化完成时将为渲染的元素隐藏
<style>
[v-cloak]{
diaplay:"none"
}
</style>
<div id="app">
<h1 v-cloak>{{message}}</h1>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"鸟飞"
}
})
</script>
v-bind
用于动态绑定属性 如:a标签的href和img标签的src
v-bind基础
<div id="app">
<a v-bind:href="link">百度一下</a>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
link:"http://www.baidu.com"
}
})
</script>
v-bind语法糖
<div id="app">
<a :href="link"></a>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
link:"http://www.baidu.com"
}
})
</script>
v-bind绑定class
对象语法
在vue中可以将一个对象绑定在class上,对象中的key的属性是true就将key的字面量当作class的类名绑定在标签的class上,false则不绑定
<div id="app">
<div v-bind:class="{class1:classq , class2:class2 , class3:class3 , class4:class4}"></div>
<!-- div最后被渲染成 <div class="class2 class3"></div> -->
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
showClass:{
class1:false,
class2:true,
class3:true,
class4:false
}
}
})
</script>
数组语法
v-bind绑定style
和绑定class的方式差不多,注意一些属性建议使用驼峰标识
对象语法
数组语法
vue配置选项
计算属性
计算属性的基本使用
主要用于对元数据进行改造输出,包括:格式化数据(价格,日期)、大写转小写、排序、添加符号
<div id="app">
<span>{{newPrice}}</span> <!-- 显示 ¥:100元 -->
<span>{{newCount}}</span> <!-- 显示 件数:10件 -->
</div>
<script>
let vm = new Vue({
el:"app",
data:{
price:100,
count:10,
},
computed:{
newPrice(){
return "¥:"+this.price+"元";
},
newCount:function(){//两种方式写的计算属性都是可以的,一种是对象增强写法
return "件数:"+this.count+"件";
}
}
})
</script>
计算属性的getter和setter
计算属性都包含get和set一般只用get方法,所以可以省略set属性。因为计算属性是属性,所以调用的时候不用加括号
<div id="app">
<h2>{{fillName}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
firstName:"鸟",
lastName:"飞",
},
computed:{
fUllName:{
get(){
console.log("我调用了fUllName的get");
return this.firstName+this.lastName;
},
set(value){
console.log("我调用了fullName的set========"+value);
this.firstName=value[0];
value.shift();
this.lastName=value;
}
}
}
})
</script>
计算属性的缓存
methods和computed虽然都能实现其数据格式的功能,但是在机制上有差异,计算属性只会调用一次,而方法会调用很多次
<div id="app">
<span>{{fullName}}</span>
<span>{{fullName}}</span>
<span>{{fullName}}</span>
<span>{{getFullName}}</span>
<span>{{getFullName}}</span>
<span>{{getFullName}}</span>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
firstName:"鸟",
lastName:"飞"
},
computed:{
fullName(){
console.log("计算属性被调用");
return this.firstName+this.lastName;
}
},
methods:{
getFullName:function (){
console.log("方法被调用");
return this.firstName+this.lastName;
}
}
})
</script>
v-on事件监听
v-on基础
用于绑定时间监听,处理前端的用户交互。比如点击、拖拽、键盘操作
<div id="app">
<button @click="btnClick">按钮</button>
<button v-on:click="btnClick()">按钮</button>
<button v-on:click="counter++"></button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
counter:0,
},
methods:{
btnClick:function(){
this.counter++;
}
}
})
</script>
v-on参数问题
- 如果不需要传入参数,方法后面的()可以不写
- 如果方法里面有参数,但是调用方法没传参数,默认将event对象传给参数
- 如果方法需要参数,同时也需要event时,可通过$event传入事件
<div id="app">
<button v-bind:click="btnClick">按钮</button>
<button @click="btnClick">按钮</button>
<button v-bind:click="readCount(count,$event)">按钮</button>
<button @click="addCount">按钮</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
count:0,
},
methods:{
btnClick:function(event){
console.log(event);
},
readCount:function(count,event){
console.log(event);
console.log(count)
},
addCount(){
this.count++;
}
}
})
</script>
v-on修饰符
在某些情况下,我们拿到event的目的可能是进行一些事情处理,Vue提供了修饰符来帮助我们方便的处理一些事情
<div id="app">
<div v-on:click="addCount">
<!-- 停止事件冒泡 -->
<button v-on:click.stop="addCount">按钮</button>
</div>
<!-- 阻止默认行为 -->
<button @click.prevent="addCount">按钮</button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 串联修饰符 -->
<button v-bind:click.once.stop.prevent="addCount">按钮</button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="addCount">
<!-- 键修饰符,键代码 -->
<input @keyup.13="addCount">
<!-- 点击回调只触发一次 -->
<button @click.once="addCount">按钮</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"石鹏飞",
count:1,
},
methods:{
addCount(){
console.log(this.count);
this.count++;
}
}
})
</script>
条件判断
v-if v-else-if v-else
v-if后面的条件为false,对应的元素以及子元素不会渲染。也就是根本不会有对应的标签出现在DOM中
<div id="app">
<div v-if="score>90">成绩优秀</div>
<div v-else-if="score>80">成绩良好</div>
<div v-else-if="score>60">成绩及格</div>
<div v-else>成绩不合格</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
score:99,
}
})
</script>
v-if的元素复用问题
现象:当下面的代码将input中的key属性去掉的时候,在useuname-input的输入框输入的值点击切换之后会在useremail-input的输入框中出出现。
原因:因为Vue在进行DOM渲染时出于性能的考虑,会尽可能地复用已存在地元素,而不是重新创建新的元素。
解决方案:如果我们不希望Vue出现类似的重复利用的问题,可以给input添加 key 。
<div id="#app">
<span v-if="username">
<lable>用户账号:</lable>
<input placeholder="用户账号" key="username-input" key="username">
</span>
<span v-else>
<lable>用户邮箱:</lable>
<input placeholder="用户邮箱" key="useremail-input" key="useremail">
</span>
<button @click="handleToggle">切换类型</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
username:true
},
methods:{
handleToggle(){
this.username=!this.username;
}
}
})
</script>
v-if和v-show
v-if和v-show都是决定元素是否进行渲染,但是决定的方式不是很相同。
- v-if条件为false时,压根不会有元素出现在DOM上
- v-show条件为false时,仅仅将元素的display属性设置为none
所以当元素切换很频繁的时候使用 v-show 切换的频率很少的时候使用 v-if
<div id="app">
<h2 v-if="isShow">我是v-if<h2>
<h2 v-show="idShow">我是v-show</h2>
<button @clack="change">显示隐藏</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
isShow:true,
},
methods:{
change:function(){
this.isShow=!this.isShow;
}
}
})
</script>
循环遍历
v-for遍历数组
- v-for="item in movies"
- 依次从movies中取出item,并且在内容中我们可以使用Mustache语法,来使用item
- v-for="(item , value) in movies"
- 其中的index表示取出的item在movies数组上的索引值
<div id="app">
<ul>
<li v-for="item in movies">{{item}}</li>
<li>------分割线------</li>
<li v-for="(value , index) in movies">{{index}}-{{value}}</li>
</ul>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
movies:["大江大河","盗梦空间","刀锋1937","谁的青春不迷茫"],
}
})
</script>
v-for遍历对象
<div id="app">
<ul>
<li v-for="(value , key , index) in personInfo">{{index+1}}-{{key}}-{{value}}</li>
</ul>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
personInfo:{
name:"鸟飞",
height:188,
weight:130,
age:18,
}
}
})
</script>
<!-- 显示
1-name-鸟飞
2-height-188
3-weight-130
4-age-18
-->
检测数组更新
在Vue中直接用数组索引对元素进行更改,(如:value[0] = 1 )是不能被Vue框架检测到并及时更新DOM(不能触发视图更新)。
<div id="app">
<ul>
<li v-for="item in nums">{{item}}</li>
</ul>
<button @click="btnclick">点击</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
nums:["wo","xian","zai","hao","fan"],
},
methods:{
btnclick:function(){
this.nums[2]="鸟飞";
}
}
})
</script>
能触发视图更新的函数
- push()
- pop()
- shift()
- unshift()
- splice()
- sore()
- reverse()
数据绑定
v-model原理
- v-bind 绑定一个value值
- v-on指令给当前元素绑定input事件
<div id="app">
<input type="text" v-model="message"><br>
<!-- v-model原理 -->
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
<h2>{{message}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"你好!鸟飞"
}
})
</script>
v-model : radio
<div id="app">
<label for="lanqiu">
<input type="radio" v-model="qiu" name="运动" value="篮球" id="lanqiu">篮球
</label>
<label for="zuqiu">
<input type="radio" v-model="qiu" name="运动" value="足球" id="zuqiu">足球
</label>
<label for="yumaoqiu">
<input type="radio" v-model="qiu" name="运动" value="羽毛球" id="yumaoqiu">羽毛球
</label>
<h2>你选择的是:{{qiu}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
qiu:"篮球"
}
})
</script>
v-model:checkbox
单个复选框
<div id="app">
<label for="show"> <input type="checkbox" v-model="isShow" id="show">是否选择 </label>
<div>
<span v-if="isShow">是</span>
<span v-else>否</span>
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
isShow:false,
}
})
</script>
多个复选框
<div id="app">
<label for="lanqiu">
<input type="checkbox" value="篮球" v-model="selects" id="lanqiu">篮球
</label>
<label for="zuqiu">
<input type="checkbox" value="足球" v-model="selects" id="zuqiu">足球
</label>
<label for="yumaoqiu">
<input type="checkbox" value="羽毛球" v-model="selects" id="yumaoqiu">羽毛球
</label>
<div>
<div>
你选择的是
</div>
<ul>
<li v-for="item in selects">{{item}}</li>
</ul>
</div>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
selects:[],
}
})
</script>
v-model:select
select单选
<div id="app">
<select v-model="select">
<option value="篮球">篮球</option>
<option value="足球">足球</option>
<option value="羽毛球">羽毛球</option>
<option value="跑步">跑步</option>
</select>
<h3>你的选择是:{{select}}</h3>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
select:"篮球"
}
})
</script>
select多选
<div id="app">
<select multiple v-model="selects">
<option value="篮球">篮球</option>
<option value="足球">足球</option>
<option value="羽毛球">羽毛球</option>
<option value="跑步">跑步</option>
</select>
<h2>你选择的是:{{selects}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
selects:[],
}
})
</script>
v-model修饰符
lazy:只在input失去焦点或者按回车键的时候才会更新数据
<div id="app">
<input type="text" v-model.lazy="message">
<h2>{{message}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"鸟飞"
}
})
</script>
number:在默认情况下,输入框默认无论我们输入的是数字还是字母,都会被当作字符串类型来处理,加上number可以让输入框的内容自动转成数字类型
<div id="app">
<input type="text" v-model="number">
<h2>number:{{typeof number}}----{{number}}</h2>
<input type="text" v-model.number="num">
<h2>num:{{typeof num}}-----{{num}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
number:0,
num:0,
}
})
</script>
trim:去除输入内容首尾的空格
<div id="app">
<input type="text" v-model="text1">
<h2>{{text1}}</h2>
<input type="text" v-model.trim="text2">
<h2>{{text2}}</h2>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
text1:"你好鸟飞",
text2:"你好鸟飞"
}
})
</script>
vue组件化开发
注册组件的基本步骤
组件的基本用法
- 创建组件构造器
- 调用Vue.component()方法
- 在Vue实例的作用范围内使用组件
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
//1.创建组件构造器
const mycomponent = Vue.extend({
template:`
<h2>我是标题</h2>
<p>我是组件的内容,我叫鸟飞,大家好啊</p>
`
})
//2.注册组件,并定义组件标签的名称
Vue.component("my-cpn",mycomponent);
let vm = new Vue{
el:"#app",
data:{
message:"鸟飞"
}
}
</script>
全局组件和局部组件
通过上一个案列演示,通过调用Vue.compontnt()注册组件时,注册的是全局组件。可以在任意的Vue实例下使用。如果我们的组件时挂在在一个Vue实例上,那么这个组件就是局部组件。
局部组件的创建方法
<div id="app">
<!-- 在Vue实例作用范围使用组件 -->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
// 1.创建组件构造器
const mycomponent=Vue.extend({
template:`
<div>
<h2>我是组件的标题</h2>
<p>我是组件的内容,哈哈哈哈哈哈哈</p>
</div>`
});
let vm = new Vue({
el:"#app",
components:{// 将组件构造器放在实例中
"my-cpn":mycompontnt,
}
})
</script>
父组件和子组件
组件和组件之间存在着层级关系,其中最终要的一种关系就是父子组件之间的关系
<div id="app">
<cpn></cpn>
</div>
<script>
// 1.创建一个子组件
const child = Vue.extend({
template:`
<div>我是子组件的内容,我是child<div>`
});
// 2.创建父组件
const parent = Vue.extend({
template:`
<div>
<h2>我是父组件的标题</h2>
<p>我是父组件的内容,我是parent</p>
<child-cpn></child-cpn>
</div>`,
components:{
"child-cpn":child
}
});
let vm = new Vue({
el:"#app",
components:{
"cpn":parent,
}
})
</script>
注册组件的语法糖
注册全局组件语法糖
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<script>
Vue.component("cpn",{
template:`
<div>
<h2>我是组件的标题</h2>
<p>我是组件的内容,今天学了注册组件的语法糖学法,好开心</p>
</div>
`
})
let vm = new Vue({
el:"#app"
})
</script>
注册局部组件语法糖写法
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<script>
let vm = new Vue({
el:"#app",
components:{
"cpn":{
template:`
<div>
<h2>我是组件标题</h2>
<p>我是组件的内容,今天学了组建的的语法糖写法,好开心啊</p>
</div>
`
}
}
})
</script>
Vue模板分离写法
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件的标题</h2>
<p>我是组件的内容,哈哈哈哈</p>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
components:{
"cpn":{
templete:"#cpn"
}
}
})
</script>
父子组件的通信
首先,每个Vue实例(组件或者是root)都有自己的data用于存放自己的数据,每个实例之间的值是不能直接访问的,需要通过对应的方法才能进行父子组件之间的数据传递。
父组件向子组件传递数据
父组件向子组件传值的数组语法
<div id="app">
<!-- 3.在组件中通过使用对象的时候将父组件中的data值传给子组件的props -->
<child-cpn v-bind:message="message"></child-cpn>
<child-cpn :message="message"></child-cpn>
</div>
<template id="child-cpn">
<div>
<h2>{{message}}</h2>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
// 1.Vue实例中的data
data:{
message:"大家好,我叫鸟飞",
},
components:{
"child-cpn":{
template:"#child-cpn",
// 2.子组件中的props
props:["message"],
}
}
})
</script>
父组件向子组件传值的对象语法
props属性中的值只能通过父组件来改变
<div id="app">
<child-cpn v-bind:message="message" :hobbys="hobbys"></child-cpn>
</div>
<template id="child-cpn">
<div>
<h2>{{message}}</h2>
<p>我的情趣爱好是</p>
<ul>
<li v-for="item in hobbys">{{item}}</li>
</ul>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"大家好,我叫鸟飞",
hobbys:["篮球","跑步","喝酒","王者荣耀"],
},
components:{
"child-cpn":{
template:"#child-cpn",
props:{
message:String,
hobbys:{
default:["王者荣耀"]
}
}
}
}
})
</script>
子组件向父组件传递数据
子组件向父组件传递数据是通过自定义事件 $emit()来讲数据传递到父组件
<div id="app">
<child-cpn v-on:add="change" v-on:jian="change"></child-cpn>
</div>
<template id="child-cpn">
<div>
<h2>{{count}}</h2>
<button v-on:click="add()">+</button>
<button @click="jian()">-</button>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
data:{
count:0,
},
methods:{
change:function(value){
this.count = parseInt(value);
}
},
components:{
"child-cpn":{
template:"#child-cpn",
data:function(){
return{
count:0
}
},
methods:{
add:function(){
this.count++;
this.$emit("add",this.count)
},
jian:function(){
this.count--;
this.$emit("jian",this.count)
}
}
}
}
})
</script>
父子组件的访问方式
有时候我们需要父组件直接访问子组件,子组件 直接访问父组件,或者子组件直接访问跟组件。就需要用到父子组件的访问方式。
父组件访问子组件:使用$children 或 $refs
<!-- $children的使用 -->
<!-- $children只能遍历子组件,并不能遍历子组件的子组件 -->
<div id="app">
<child-cpn></child-cpn>
<button @click="showChild()">显示子组件</button>
</div>
<template id="child-cpn">
<div>
<h2>{{message}}</h2>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"大家好,我叫鸟飞"
},
methods:{
showChild(){
console.log(this.$children)
}
},
components:{
"child-cpn":{
template:"#child-cpn",
data:function(){
return{
message:"我是子组件"
}
}
}
}
})
</script>
$children的缺陷
- 通过$children来访问子组件时,是一个数组类型,访问其子组件必须通过索引值
- 但是当子组件过多,我们需要拿其中一个时,往往不能确定他的索引值,甚至还可能发生变化。
- 所以可以通过$refs来取特定的组件
<!-- $refs的使用 -->
<div id="app">
<child-cpn ref="aaa"></child-cpn>
<button @click="showChild()">显示子组件</button>
</div>
<template id="child-cpn">
<div>
<h2>{{message}}</h2>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"大家好,我是鸟飞"
},
methods:{
showChild:function(){
console.log(this.$refs.aaa);
console.log(this.$refs);
}
},
components:{
"child-cpn":{
template:"#child-cpn",
data:function(){
return{
message:"我是子组件"
}
}
}
}
})
</script>
子组件访问父组件
注意事项
- 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。
- 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高。
- 如果将子组件放在另一个父组件之内,很可能引起父组件没有对应的属性,往往会引起问题。
- 另外更不能通过$parent来直接修改父组件的状态,那么父组件的状态将变得飘忽不定,不利于调试和维护。
<!-- $parent -->
<div id="app">
<child-cpn></child-cpn>
</div>
<template id="child-cpn">
<div>
<h2>{{message}}<h2>
<button @click="showparent">显示父子间</button>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"大家好,我是鸟飞",
},
components:{
"child-cpn":{
template:"#child-cpn",
data:function(){
return{
message:"我是子组件"
}
},
methods:{
showparent:function(){
console.log(this.$parent)
}
}
}
}
})
</script>
插槽的使用
插槽的简单使用
<div id="app">
<child-cpn></child-cpn>
<child-cpn>
<template slot="title"><h2>我是标题</h2></template>
<template slot="msg"><p>大家好,我叫鸟飞,我是组件的内容。</p></template>
</child-cpn>
</div>
<template id="child-cpn">
<div>
<slot name="title"><h2>我是组件的标题插槽</h2></slot>
<slot name="msg"><p>我是组件的内容插槽</p></slot>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
components:{
"child-cpn":{
template:"#child-cpn"
}
}
})
</script>
插槽数据处理
适用于Vue2.6以上版本
<div id="app">
<child-cpn></child-cpn>
<child-cpn>
<template slot="title">
<h2>兴趣爱好</h2>
</template>
<template slot="hobby" v-slot:hobby="slotProps">
<span>{{slotProps.hobby.join("-")}}</span>
</template>
</child-cpn>
</div>
<template id="child-cpn">
<div>
<slot name="title"><h2>我是标题</h2></slot>
<slot name="hobby" v-bind:hobby="hobby">
<ul>
<li v-for="item in hobby">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
let vm = new Vue({
el:"#app",
components:{
"child-cpn":{
template:"#child-cpn",
data(){
return{
hobby:["篮球","羽毛球","足球","乒乓球","桌球"]
}
}
}
}
})
</script>