这次的 Vue基础篇 会从 4个方向 1个项目 来 汇总.
一. 基本语法
1. 数据的对象格式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<p>{{student.name}}今年{{student.age}}岁,是{{student.sex}}的</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: "#app",
data: {
student : {
name : '张三',
age : 23,
sex : '男'
}
}
})
</script>
2. 双向绑定
要求: 输入框输入数据,会显示到h3元素上,分别通过js和vue实现
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<h3>{{msg}}</h3>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
// v-model 指令
new Vue({
el: "#app",
data: {
msg : ""
}
})
</script>
效果图:
3. 简易实现双向数据绑定(原生js实现vue双向绑定)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<body>
<input type="text" value="" id="ipt" oninput="iptChange(this.value)">
<h3 id="title" ></h3>
</body>
</html>
<script>
// 获取元素
var ipt = document.getElementById('ipt')
var title = document.getElementById('title')
// 声明一个data对象 专门用来放数据
var data = {};
// 用来给对象添加属性 define(定义) Property(属性)
// Object.defineProperty(对象的名称,属性的名称,配置项)
Object.defineProperty(data, 'msg', {
// get方法: 定义这个msg时要赋值的数据
get: function () {
return '你好世界'
},
// set方法: 代表当你拿到最新的值时,需要做的事
set: function (newVal) {
title.innerHTML = newVal
ipt.value = newVal
console.log(newVal);
}
})
// console.log(data.msg);
// 初始样式
title.innerHTML = data.msg
ipt.value = data.msg
// input的value值发生改变
function iptChange(val) {
data.msg = val // 修改数据源 会自动触发set方法
}
</script>
效果图: 实现出来的效果和vue的效果为一样的
4. Vue中的MVVM
1). View层:
视图层,在前端里就是我们常说的DOM层,主要作用是给用户展示各种信息;
2). Model层:
数据层(逻辑层),数据可能是我们自定义的数据,或者是从网络请求下来的数据;
3). ViewModel层:
视图模型层,是View层和Model层沟通的桥梁;一方面它实现了数据绑定(Data Binding),将Model的改变实时反应到View中;另一方面它实现了DOM监听,当DOM发生改变可以对应改变数据(Data)
5. v-pre
概念: 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
通俗易懂一点: 让胡子语法失效 显示出该有的{{}}内容
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- v-pre: 让胡子语法失效 显示出该有的{{}}内容 -->
<p>当你输入<span v-pre>{{msg}}</span>的时候,你就可以看到{{msg}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: "#app",
data: {
msg : "你好世界"
}
})
</script>
效果图:
6. v-html 和 v-text
概念: 胡子语法与v-text是一样的,都无法解析html标签 , v-html比较强大 可以将html标签解析出来
v-html不仅可以渲染数据,而且可以解析标签
v-text和{{}}表达式渲染数据,不解析标签
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<!--
胡子语法与v-text是一样的,都无法解析html标签
v-html比较强大 可以将html标签解析出来
-->
<div id="app">
<ul>
<li>{{msg}}</li>
<li v-html="msg"></li>
<li v-text="msg"></li>
<div>------------</div>
<li>{{msg}}</li>
<li v-html="content"></li>
<li v-text="content"></li>
</ul>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg:"你好世界",
content:"<b>hello world</b>"
}
})
</script>
效果图:
7. v-cloak
概念: v-cloak指令用于在数据渲染出来之前 将标签隐藏掉 这样用户就看不到胡子语法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<!-- v-cloak指令用于在数据渲染出来之前 将标签隐藏掉 这样用户就看不到胡子语法 -->
<div id="app">
<ul>
<li>{{msg1}}</li>
<li v-cloak>{{msg2}}</li>
</ul>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg1:'你好世界1',
msg2:'你好世界2'
}
})
</script>
8. v-show 与 v-if
v-show 和 v-if的区别:
1). 显示和隐藏:
v-show 的显示隐藏控制的是css的display属性
v-if 的显示隐藏时通过创建和销毁dom元素实现的
从性能上讲 v-show性能更好 而v-if会造成性能浪费
2). 使用场景:
当需要频繁切换一个元素的显示隐藏时,使用v-show
当一次性渲染元素并且再也不需要修改,那么两者都行
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style>
.box{width: 100px;height: 100px;background-color: red;}
</style>
</head>
<body>
<div id="app">
<div class="box" v-show="flag"></div>
<div class="box" v-if="flag2"></div>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
flag : true,
flag2 : false
}
})
</script>
我们通过控制台可以看到 v-if的元素被销毁了 v-show的元素只是加了style
9. v-on
为元素绑定事件可以直接在元素上 v-on:click="方法名称()" ,或者简写成 @click="方法名称()"
对应的方法要写在Vue对象中的 methods 中,在指令中想要访问data属性中的数据,可以通过this加上自己定义的属性名即可,this.自定义属性名称
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style>
.box{width: 100px;height: 100px;background-color: red;}
</style>
</head>
<body>
<div id="app">
<div>
<button @click='btnClick'>按钮</button>
<div class="box" v-show='flag'></div>
</div>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
// data是专门用来存放数据的地方
data: {
flag : true
},
// methods是专门用来存放方法的地方
methods:{
btnClick(){
// 控制盒子的显示隐藏,本质上是控制盒子的true和false
console.log(this);
this.flag = !this.flag
}
}
})
</script>
效果图:
二. 常用指令
1. v-bind
v-bind 和 v-on 一样也有简写的方式,v-bind:src="" 可以简写成 :src=""
1.1 属性绑定
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<a :href="link" v-text="msg"></a>
<button @click="gobili">切换到B站</button>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
link : "http://baidu.com",
msg:'百度一下'
},
methods:{
gobili(){
this.link = "http://bilibili.com"
this.msg = '哔哩哔哩'
}
}
})
</script>
效果图:
1.2 类名绑定
绑定class有两种方式:对象语法,数组语法。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style>
.green{
color: green;
}
.italic{
font-style: italic;
}
</style>
</head>
<body>
<div id="app">
<p class="green">绿</p>
<p v-bind:class="{'green':isgreen}">绿</p>
<p :class="{'green':isgreen,'italic':isItalic}">绿</p>
<h3 :class="greenplay ? 'green italic' : '' ">绿色 -- 重要</h3>
<p :class="['green','italic']">绿</p>
<p :class="setItalic()">绿</p> <!-- 括号代表立即执行 -->
<button v-text='msg' @click="huan"></button>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
greenplay:true,
isgreen:true,
isItalic:true,
msg : '切换false',
flag : true
},
methods:{
setItalic(){
return ['green','italic']
},
huan(){
if(this.flag){
this.greenplay = false
this.msg = '切换为true'
}else{
this.greenplay = true
this.msg = '切换为false'
}
this.flag = !this.flag
}
}
})
</script>
效果图:
1.3 style绑定
注意点:
- 我们可以使用驼峰式语法:比如
font-size--->fontSize - 或短横线分隔
font-size
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li style="background-color: pink; color:orange;">背景粉,文字橙</li>
<li :style="{'background-color':bgColor,color:fontColor}">背景粉,文字橙</li>
<li :style="colorObj">背景粉,文字橙</li>
<li :style="[colorObj,fontStyle]">背景粉,文字橙</li>
<li :style="getStyle()">背景粉,文字橙</li>
<!-- 对象的key值是字符串 background-color -会被浏览器默认成减号-->
<!--
解决方法:
加''变成字符串
驼峰式
-->
</ul>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
bgColor:'pink',
fontColor:'orange',
colorObj:{background:'pink',color:'orange'},
fontStyle:{fontSize:'20px'}
},
methods:{
getStyle(){
return [this.colorObj,this.fontStyle]
}
}
})
</script>
效果图:
2. 循环遍历v-for以及key的使用
v-for语法: v-for="(item,index) in 数组名"
item 对应的是数组中的每一条数据
index 索引(下标)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<!--
key作为唯一标识符,如果选用index,那么他就失去了唯一性
index在数组发生变化时,它自己也会发生变化,所以当数组是会变化的时候,尽量不要选择index作为key
总结:
当数组不发生变化时(一次性渲染)key可以选用index或者id
当数组会发生变化时,这时候会引起html的重排,此时不要选用index,最好选择id
-->
<div id="app">
<ul>
<li v-for="(item,index) in arr" :key="item.id">{{item.name}} <input type="checkbox"></li>
</ul>
<button @click="unshiftOne">追加元素</button>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
arr: [
{ id:1,name: '张三' },
{ id:2,name: '李四' },
{ id:3,name: '王五' },
]
},
methods:{
unshiftOne(){
this.arr.unshift({ id: 4, name: '狗蛋' })
}
}
})
</script>
效果图: 实现一个在前添加元素的效果
3. 计算属性
computed中写需要计算的函数
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li>姓:{{xing}}</li>
<li>名:{{ming}}</li>
<li>姓名: <input type="text" v-model="username"></li>
</ul>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
xing: 'Michael',
ming: 'Jackson',
// data里的数据时没有办法调用data里的数据的
// username : xing + ming
},
computed: {
username: {
get() {
return this.xing + ' ' + this.ming
},
set(newVal) {
// 当username的值发生改变时,会自动触发setter
console.log(newVal); // 字符串; 'Michael Jack'
let arr = newVal.split(' ') // ['Michael','Jack']
this.xing = arr[0]
if (this.ming === undefined) {
this.ming = ''
return
} else {
this.ming = arr[1]
}
}
}
}
})
</script>
效果图:
computed 与 methods 的区别
computed: 执行1次,因为computed有缓存
methods : 调用多少次就执行多少次,因为methods没缓存
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li>姓:{{xing}}</li>
<li>名:{{ming}}</li>
<li>[computed]姓名:{{username}}</li>
<li>[computed]姓名:{{username}}</li>
<li>[methods]姓名:{{username1()}}</li>
<li>[methods]姓名:{{username1()}}</li>
<li>[methods]姓名:{{username1()}}</li>
</ul>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
xing: 'Michael',
ming: 'Jackson',
},
computed: {
username() {
console.log('computed');
return this.xing + ' ' + this.ming
}
},
methods: {
username1() {
console.log('methods');
return this.xing + ' ' + this.ming
}
}
})
</script>
效果图:
4. v-model原理
v-model 其实是个语法糖,它背后本质上包含了两个操作:
v-bind绑定input元素的value属性v-on指令绑定input元素的input事件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- <input type="text" v-model="msg"> -->
<!-- <input type="text" v-bind:value="msg" v-on:input="iptChange"> -->
<!-- $event代替事件中的e -->
<input type="text" :value="msg" @input="msg=$event.target.value">
<h3>{{msg}}</h3>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg : '你好世界'
},
methods:{
iptChange(e){ // e 事件对象 元素 dom对象
// 修改msg
this.msg = e.target.value
}
}
})
</script>
效果图:
5. 数组操作
数组操作从刚开始学习js就一直再用,就不写效果图和代码了,简单的总结几个常用的...
push: 从数组的后面添加,返回被删除的数据
pop: 从数组的后面删除
unshift: 从数组的前面添加,返回被删除的数据
shift: 从数组的前面删除
splice: 替换,删除
forEach: 循环(没有返回值)
map: 循环(有返回值)
filter: 过滤
reduce: 叠加
6. 自定义过滤器
全局过滤器
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!--
完成效果:
<h3>¥21.80元</h3>
-->
<h3>{{price | filterMoney}}</h3>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
// 过滤器
// Vue.filter(过滤器名称,回调函数)
Vue.filter('filterMoney', val => {
// toFixed 数字的方法 去小数点后(位数)
// 最好先将 val转为数字类型 不然有些情况会报 toFixed is not function
return '¥' + Number(val).toFixed(2) + '元'
})
new Vue({
el: "#app",
data: {
price: 21.8
}
})
</script>
效果图:
局部过滤器
局部过滤器和全局过滤器差别不大,唯一的区别就是全局过滤器可以全部共享
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!--
完成效果:
<h3>¥21.80元</h3>
-->
<h3>{{price | filterMoney}}</h3>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
price: 21.8
},
filters: {
filterMoney(val) {
return '¥' + val.toFixed(2) + '元'
}
}
})
</script>
效果图:
7. 本地存储
localStorage永久存储
// 添加数据;setItem的value值是字符串类型的数据
localStorage.setItem('name','张三');
// 获取数据
localStorage.getItem('name'); // 张三
// 删除数据
localStorage.removeItem('name');
// 清空
localStorage.clear();
sessionStorage临时会话存储
// 添加数据;setItem的value值是字符串类型的数据
sessionStorage.setItem('name','张三');
// 获取数据
sessionStorage.getItem('name'); // 张三
// 删除数据
sessionStorage.removeItem('name');
// 清空
sessionStorage.clear();
cookie
需要用live server打开
添加: document.cookie = 'username="张三"'
三. 指令与传值
1. 数据劫持(对象属性的配置)
value 给某个key添加值
writable 设置某个key可否被修改,默认为false
configurable 设置某个key可否被删除,默认为false
enumerable 设置当前对象能否枚举所有属性,默认为false
let obj = {}
Object.defineProperty(obj,'msg',{
value : '你好世界',
writable : true,
configurable : true,
enumerable : true
})
console.log(obj.msg); // 你好世界
obj.msg = 'hello world'
// 删除一个属性
// delete obj.msg
console.log(obj.msg);
// 枚举(罗列)一个对象的属性
console.log(Object.keys(obj));