一.认识Vue
Vue 是一套用于构建用户界面的渐进式框架。
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
<div id="app">{{msg}}</div>
<script>
const app = new Vue({
el:'#app',
data(){
return {
msg:'Hello Vue!'
}
}
})
</script>
现在数据和 DOM 已经被建立了关联,所有东西都是响应式的
其中html里大括号里面可以写变量或者有返回值的表达式,从而变成动态的
js里是实例化Vue对象,通过el绑定元素,将Vue对象里的属性和方法也挂载到元素上
二.vue常用指令
1.v-bind绑定属性
<div id="app">
<span :title="msg">鼠标放在这里</span>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
msg:`页面加载于${new Date().toLocaleString()}`
}
}
})
</script>
2.v-if判断
<div id="app">
<!-- v-if可以判断vue实例的seen属性控制这个元素彻底消失 相当于把这个元素节点注释了-->
<p v-if="seen">1111</p>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
seen:true
}
}
})
</script>
3.v-for遍历
<div id="app">
<ul>
<!-- 这里相当于for of遍历 也可以用for in 写 -->
<li v-for="item of arr">{{item}}</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
arr:['a','b','c']
}
}
})
</script>
4.v-on绑定事件
<div id="app">
<h1>{{num}}</h1>
<!-- v-on 为元素绑定事件 类似onclick -->
<!-- <button v-on:click="add">增加</button> -->
<!-- 语法糖 -->
<button @click="add">增加</button>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
num:0
}
},
methods:{
add(){
this.num++
}
}
})
</script>
5.v-model表单双向绑定
<div id="app">
<h1>{{msg}}</h1>
<!-- 变量变页面跟着变,但页面变变量不会变,v-model实现了用户在输入表单时的双向绑定 -->
<!-- input.value <===> v-model <===> msg -->
<input type="text" name="" id="" v-model="msg">
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
msg:'11111'
}
}
})
</script>
三.动态绑定属性
1.回顾v-bind
<div id="app">
<span :title="msg">鼠标放在这里</span>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data(){
return {
msg:`页面加载于${new Date().toLocaleString()}`
}
}
})
</script>
2.用对象的方式动态绑定class
<style>
.a{
color: red;
}
</style>
<div id="app">
<!-- 引号里面其实是 {类名:布尔值} true就添加类名,false不添加 -->
<h2 :class="getactive()">{{msg}}</h2>
<button @click="changeActive">点击变色</button>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
msg:'我是2208班学生',
isactive:false
}
},
methods:{
getactive(){
return {a:this.isactive}
},
changeActive(){
this.isactive = !this.isactive
}
}
})
</script>
3.用数组的方式动态绑定class
<div id="app">
<h2 :class="['a','b']">这是虽然绑定但不是变量的类名</h2>
<h2 :class="[a,b]">这是绑定变量的类名</h2>
<h2 :class="getClasses()">这是封装成方法</h2>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
return{
a:'aaa',
b:'bbb'
}
},
methods:{
getClasses(){
return [this.a,this.b]
}
}
})
</script>
4.v-for与v-bind的结合使用
<style>
.chosed{
color: red;
}
</style>
</head>
<body>
<div id="app">
<ul> <!--对象的键是类名,类名添不添加由对象的值(布尔)决定 -->
<li v-for="(item,index) in movies" :key="index" :class="{chosed:index==choseIndex}" @click="change(index)">{{item}}</li>
</ul> <!--这里把当前li的索引作为形参传过去-->
<ul>
<li v-for="(item,index) in movies" :key="index" :class="index==choseIndex?'chosed':''">{{item}}</li>
</ul> <!--三元表达式写法-->
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
movies:["海王", "海贼王", "火影忍者", "复仇者联盟"],
choseIndex:0
}
},
methods:{
change(index){
this.choseIndex = index
}
}
})
</script>
</body>
5.用对象方式动态绑定style
<div id="app">
<h2 :style="{fontSize:'50px',color:'red'}">这里虽然绑定了但是没什么意义还是死的</h2>
<h2 :style="{color:mycolor}">这里绑定了变量</h2>
<h2 :style="getStyle()">这里在绑定的同时封装了一下</h2>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
mycolor:'blue'
}
},
methods:{
getStyle(){
return {'color':this.mycolor}
}
}
})
</script>
6.用数组方式动态绑定style
<div id="app">
<h2 :style="[style1,style2]">数组方式可以将多个样式作为变量放进数组里</h2>
<h2 :style="getStyle()">这里也可以封装一下</h2>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
return {
style1:{color:'red'},
style2:{fontSize:'50px'}
}
},
methods:{
getStyle(){
return [this.style1,this.style2]
}
}
})
</script>
四.计算属性与侦听器
1.计算属性的基本使用
<div id="app">
<h2>{{firstName}}-{{lastName}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{FullName}}</h2> <!--计算属性是一个属性不需要加括号调用-->
</div>
<script src="./vue.js"></script>
<script>
const Vm = new Vue({
el:'#app',
data(){
return {
firstName:'邬',
lastName:'浩'
}
},
// 方法 一般用于事件
methods:{
getFullName(){
return this.firstName + '-' + this.lastName
}
},
// 计算属性
//this指向Vue实例,与data间存在数据代理
computed:{
FullName(){
return this.firstName + '-' + this.lastName
}
},
// 监听器 监听属性变化
watch:{}
})
</script>
2.计算属性的复杂使用
<div id="app">
<h2>{{totalPrice}}</h2>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
books: [{
id: 110,
name: "JavaScript从入门到入土",
price: 119
},
{
id: 111,
name: "Java从入门到放弃",
price: 80
},
{
id: 112,
name: "编码艺术",
price: 99
},
{
id: 113,
name: "代码大全",
price: 150
}
]
}
},
methods: {
},
computed: {
// 1.for循环
// totalPrice(){
// let total = 0
// for(let i = 0; i < this.books.length; i++){
// total += this.books[i].price
// }
// return total
// }
// 2.for of
// totalPrice() {
// let total = 0
// for (let item of this.books) {
// total += item.price
// }
// return total
// }
// 3.for in
// totalPrice() {
// let total = 0
// for (let i in this.books) {
// total += this.books[i].price
// }
// return total
// }
// 4.foreach
// totalPrice() {
// let total = 0
// this.books.forEach(item => total += item.price)
// return total
// }
//5.map
// totalPrice() {
// let total = 0
// this.books.map(item => total += item.price)
// return total
// }
//6.filter
// totalPrice() {
// let total = 0
// this.books.filter(item => total += item.price)
// return total
// }
// 7.reduce
totalPrice() {
return this.books.reduce((total,item)=>total + item.price,0)
}
},
watch: {
}
})
</script>
3.计算属性的setter和getter
<div id="app">
<h2>{{firstName}}-{{lastName}}</h2>
<h2>{{fullName1}}</h2>
<h2>{{fullName2}}</h2>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
firstName: '邬',
lastName: '浩'
}
},
methods: {},
computed: {
//常用写法
fullName1() {
return this.firstName + '-' + this.lastName
},
// 底层
fullName2: {
//当页面调用计算属性时,get方法执行,返回拼接后的结果
get(){
return this.firstName + '-' + this.lastName
},
//拼接后的值被改变时,set方法执行,将原数据跟着改变 计算属性一般是没有set方法的 对Vue压力过大
set(value){
console.log(value); //value是改变后的值
let temp = value.split('-') //将其分割
this.firstName = temp[0]
this.lastName = temp[1]
}
}
},
watch: {}
})
</script>
4.计算属性与方法的对比
<div id="app">
<div>
计算属性
<p>{{FullName}}</p>
<p>{{FullName}}</p>
<p>{{FullName}}</p>
</div>
<br><br>
<div>
方法
<p>{{getFullName()}}</p>
<p>{{getFullName()}}</p>
<p>{{getFullName()}}</p>
</div>
<p>总结:方法必须要加括号调用,而且页面写一个就要调用一次 <br>
计算属性写多少个都只调用一次只有值改变才会再次调用</p>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
firstName: '邬',
lastName: '浩'
}
},
methods: {
getFullName(){
console.log('调用了方法');
return this.firstName + this.lastName
}
},
computed: {
FullName(){
console.log('调用了计算属性');
return this.firstName + this.lastName
}
},
watch: {}
})
</script>
5.监听器
<div id="app">
<p>1{{firstName+lastName}}</p>
<p>2{{watchFullName1}}</p> <!--监听器只有被监听的值改变才会调用 所以这里不显示-->
<p>3{{watchFullName2}}</p> <!--立即调用一次-->
<p>4{{watchFullName3}}</p>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
firstName: '邬',
lastName: '浩',
watchFullName1:'',
watchFullName2:'',
watchFullName3:''
}
},
methods: {
change(){
return this.watchFullName3 = this.firstName + this.lastName
}
},
computed: {
},
watch: {
// 监听姓,姓改变姓名也变
firstName(newVal,oldVal){
console.log(newVal) //姓被改变后的值
console.log(oldVal)
this.watchFullName1 = this.firstName + this.lastName
},
//完全写法
lastName:{
handler(newv,oldv){
this.watchFullName2 = this.firstName + this.lastName
},
immediate:true //立即监听
},
//监听属性改变时调用方法(监听与方法结合使用)
watchFullName3:'change'
}
})
// 外部监听写法
// VM.$watch('firstName',(n,o)=>{
// console.log(n)
// console.log(o);
// })
</script>
6.监听复杂数据类型
<div id="app">
<h2>{{person.fullName}}</h2>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
person:{
firstName:'邬',
lastName:'浩',
fullName:''
}
}
},
methods: {},
computed: {},
watch: {
person:{
handler(n,o){
console.log(n);
console.log(o);
this.person.fullName = n.firstName + n.lastName
},
// immediate:true
deep:true //深度监听,复杂数据类型看的是地址,只要地址没变监听器就不会监听到
}
}
})
</script>
7.解决监听复杂数据类型时新老值相同的问题
<div id="app">
<p>FullName: {{fullName}}</p>
<p>FirstName: <input type="text" v-model="person.firstName"></p>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
person: {
firstName: '邬',
lastName: '浩',
}
}
},
methods: {
},
computed: {
fullName() {
return this.person.firstName + this.person.lastName
},
person2(){
// 将复杂类型转json再转回对象 监听这个操作后的对象来解决新老值相同的问题
return JSON.parse(JSON.stringify(this.person))
}
},
watch: {
// 不再监听data中的person,而是监听处理过的计算属性 同时也不再需要deep深度监听 因为person2会完全跟着person变
person2:{
handler(n,o){
console.log('被修改了');
console.log(n);
console.log(o);
}
}
}
})
</script>
五.事件监听与事件修饰符
1.回顾v-on与参数传递
<div id="app">
<button @click="demo()">未定义参数</button>
<button @click="demo('111')">传参</button>
<button @click="demo">传事件对象</button>
<button @click="demo($event,'111')">传参加事件对象</button>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
}
},
methods: {
demo(){
}
},
computed: {},
watch: {}
})
</script>
2.事件修饰符
<div id="app">
<h2>1. .stop阻止事件冒泡(禁止由内到外)</h2>
<div @click="demo1">
<span @click.stop="demo1">点我冒泡</span>
</div>
<h2>2. .prevent阻止默认事件</h2>
<a href="www.baidu.com" @click.prevent="demo1">点我跳转</a>
<h2>3. .enter监听键盘事件</h2>
<input type="password" name="" id="" @keyup.enter="submit">
<h2>4. .once事件只允许调用一次</h2>
<button @click.once="demo2">只能点一次</button>
<h2>5. .capture开启捕获模式(由外到内)</h2>
<div @click.capture="demo1">
<span @click="demo2">点我捕获</span>
</div>
<h2>6. .self 当事件对象是当前操作的元素时才触发事件</h2>
<div @click.self="demo1">
<span @click="demo2">点我才触发(本应冒泡也触发demo1)</span>
</div>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
}
},
methods: {
demo1(){
console.log(1);
},
submit(){
console.log(2);
},
demo2(){
console.log(3);
}
},
computed: {},
watch: {}
})
</script>
六.条件判断
1.回顾v-if 和v-else、 v-else-if
<div id="app">
<h2 v-if="age<18">未成年</h2>
<h2 v-else-if="age<60">成年</h2>
<h2 v-else="">暮年</h2>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
age:20
}
},
methods: {},
computed: {},
watch: {}
})
</script>
2.v-if实例
<!-- 逻辑和原生一样通过flag和if判断控制显示,只是写法不一样 -->
<div id="app">
<label v-if="flag" key="a">
用户名
<input type="text" name="" id="">
</label>
<label v-else="flag" key="b">
密码
<input type="password" name="" id="">
</label>
<button @click="change">切换类型</button>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
flag: true
}
},
methods: {
change() {
this.flag = !this.flag
}
}
})
// 切换到邮箱输入,输入框未自己清空。
// 这里需要了解一下vue底层操作,此时input输入框值被复用了。
// 1.vue在进行DOM渲染是,处于性能考虑,会复用已经存在的元素,而不是每次都创建新的DOM元素。
// 2.在上面demo中,Vue内部发现原来的input元素不再使用,所以直接将其映射对应虚拟DOM,用来复用。
// 3.如果不希望出现类似复用问题,可以给对应的dom元素加上key值,并保证key不同。
3.v-show与v-if的区别
<div id="app">
<!-- v-if 在首次渲染的时候,如果条件为假,什么也不操作,页面当作没有这些元素。当条件为真的时候,开始局部编译,动态的向DOM元素里面添加元素。当条件从真变为假的时候,开始局部编译,卸载这些元素,也就是删除。 -->
<!-- v-show 不管条件是真还是假,第一次渲染的时候都会编译出来,也就是标签都会添加到DOM中。之后切换的时候,通过display: none;样式来显示隐藏元素。可以说只是改变css的样式,几乎不会影响什么性能。 -->
<h2 v-show="flag">v-show只是操作元素的style属性display</h2>
<h2 v-if="flag">v-if是新增和删除dom元素</h2>
</div>
<script src="./vue.js"></script>
<script>
const VM = new Vue({
el: '#app',
data() {
return {
flag:true
}
}
})
</script>
七.循环遍历
1.回顾v-for循环
<div id="app">
<ul>
<!-- 这里的i不是索引是每一项 -->
<li v-for="i in names">{{i}}</li>
</ul>
<br><br>
<ul>
<li v-for="(item,key,index) in user">{{index}}--{{key}}--{{item}}</li>
</ul>
<br><br>
<ul>
<li v-for="(item,index) in names">{{index}}--{{item}}</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
names: ["zzz", "ttt", "yyy"],
user: {
name: "zzz",
height: 188,
age: 24
}
}
}
})
</script>
2.v-for与key
<div id="app">
<ul>
<li v-for="(item,index) in title" :key="item.id">{{item.name}}--<input type="text"></li>
</ul>
<button type="button" @click="add">++</button>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
list: { id: 5, name: '赵六' },
title: [{
id: 1,
name: '张三',
},
{
id: 2,
name: '李四',
},
{
id: 3,
name: '王五',
}
]
}
},
methods: {
add() {
this.title.unshift(this.list)
}
}
})
// 总结:Vue中存在虚拟dom,当列表数据发生变化时,Vue会拿着每一个li的key去跟虚拟dom中相同key的li作比较(diff算法)
// 相同的地方就复用,比如表单和表单里的值全都被复用,不同的才会改,这也是Vue高性能的原因,不需要重新渲染,而是哪里变改一下那里就好了
3.数组奇怪的响应方式
<div id="app">
<ul>
<li v-for="item in letters">{{item}}</li>
</ul>
<button @click="btn">替换</button><br>
<button @click="btn2">替换2</button>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
letters: ['a', 'b', 'c', 'd', 'e']
}
},
methods: {
btn() {
// 直接操作数组,虽然数组发生了变化,但没有响应到页面上
this.letters[1] = 'f'
console.log(this.letters);
},
btn2() {
// 通过Vue重写的一些数组方法,会正常响应到页面上
this.letters.splice(1,1,'f')
console.log(this.letters);
}
}
})
</script>
八.双向绑定
1.回顾v-model
<div id="app">
<h2>{{msg}}</h2>
<input type="text" v-model="msg" />
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: '张三'
}
}
})
</script>
2.v-model的原理
<div id="app">
<h2>{{msg}}</h2>
<!-- oninput事件表单值发生变化时立即触发 -->
<!-- 触发时通过事件对象把当前的value赋值给msg,实现了页面改变==>数据也改变 , 本来只单向绑定了数据==>页面 -->
<input type="text" :value="msg" @input="changeMsg"/>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg:'张三'
}
},
methods: {
changeMsg(e){
this.msg = e.target.value
console.log(e);
}
},
computed:{
}
})
</script>
3.双向绑定单选
<div id="app">
<!-- name保证是一组单选,value区分选中的哪一个(也是当前这组单选的状态),v-model实现了当单选的状态改变时,把当前状态(value)赋值回数据 -->
<label>男<input type="radio" name="sex1" value="男" v-model='sex' /></label>
<label>女<input type="radio" name="sex1" value="女" v-model='sex' /></label>
<h2>您的性别是:{{sex}}</h2>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
sex:'男'
}
}
})
</script>
4.双向绑定多选框
(1)简单的双向绑定多选框
<div id="app">
<label>
<!-- 将多选value双向绑定,默认false-->
<input type="checkbox" v-model="agree" />同意协议
</label>
<!-- 由于双向绑定,用多选的状态来控制btn是否禁用 -->
<button :disabled="!agree">下一步</button>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
agree: false
}
}
})
</script>
(2)双向绑定多个多选框
<div id="app">
<h2>多选框</h2>
<!-- value表示每个选项的值,v-model给每个选项双向绑定同一个变量 -->
<!-- value的值在数组当中,就会选中这一项。这一过程是双向的,在勾选时value 的值也会自动 push这个数组中 -->
<input type="checkbox" value="篮球" v-model="hobbies" />篮球
<input type="checkbox" value="足球" v-model="hobbies" />足球
<input type="checkbox" value="羽毛球" v-model="hobbies" />羽毛球
<input type="checkbox" value="排球" v-model="hobbies" />排球
<h2>您的爱好是:{{hobbies}}</h2>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
hobbies: []
}
}
})
</script>
(3)升级版(动态绑定值,并且与v-for结合起来)
<div id="app">
<h2>多选框</h2>
<!-- 遍历数据形成表单 -->
<label v-for="(item,index) in hobbies" :for="item">
<!-- 动态绑定值,值为true添加到数组里 -->
<input type="checkbox" :value="item" :id="item" v-model="choseHobbies" />{{item}}
</label>
<h2>你的爱好是:{{choseHobbies}}</h2>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
choseHobbies: [],
hobbies: ["篮球", "足球", "乒乓球", "羽毛球"]
}
})
</script>
5.双向绑定下拉框
<div id="app">
<!-- select单选 -->
<!-- 默认选择苹果 -->
<select name="fruit" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="西瓜">西瓜</option>
</select>
<h2>你选择的水果是:{{fruit}}</h2>
<!-- select多选 -->
<!-- true就将 value push 进数组 -->
<select name="fruits" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="西瓜">西瓜</option>
</select>
<h2>你选择的水果是:{{fruits}}</h2>
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
fruit: "苹果",
fruits: []
}
})
</script>
6.双向绑定的修饰符
<div id="app">
<!-- 默认情况是实时更新数据,加上lazy,从输入框失去焦点,按下enter都会更新数据 -->
<input type="text" v-model.lazy="msg" />
<h2>{{msg}}</h2>
<!-- value默认是string类型,加上number转为number类型 -->
<input type="number" v-model.number="age">
<h2>{{age}}--{{typeof age}}</h2>
<!-- 加上trim自动过滤用户输入的首尾空白字符 -->
<input type="text" v-model.trim="name">
</div>
<script src="vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
msg: '张三',
age: 18,
name: '李四'
}
}
})
</script>