1. Vue概述
MVVM模式通过视图与模型的双向绑定简化前端操作,渐进式框架
2. 搭建工程
vue前端框架,是一个js文件;下载js文件并在页面中引用
vue.js下载方式:
- 引用在线vue.js
- 离线下载vue.js
- npm包资源管理器,可以下载vue.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--导入本地vue-->
<script src="vue/vue-2.6.10.js"></script>
<!--Vue-->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>-->
</head>
<body>
<div id="app">
<h2>{{name}}程序员</h2> <!--插值-->
<input type="text" v-model="num"> <!--input 和 num , 通过 v-model 双向绑定-->
<button v-on:click="num++">点击</button> <!-- v-on 绑定点击事件,每次点击 num++ -->
<h2>数量为{{num}}</h2>
</div>
<script>
var app = new Vue({
el:"#app", <!--要渲染的页面元素为 app-->
data:{
name:"Java",
num:1
}
});
</script>
</body>
</html>
3.Vue实例生命周期及钩子函数
创建实例可以指定模板id、数据和方法
在实例化、模板渲染过程中操作可以使用钩子函数
钩子函数:是在Vue实例生命周期过程中的不同阶段,钩子函数通过一些特定的函数对vue实例进行操作。
具体生命周期及钩子函数请参考:https://blog.csdn.net/focusmickey/article/details/108750466
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
信息是:{{msg}}
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
msg:""
},
<!--钩子函数 created() -->
created(){
this.msg= "Vue实例初始化msg为空,通过created()钩子函数进行操作赋值";
console.log(this); <!--打印出this,应该是vue实例对象-->
}
});
</script>
</body>
</html>
4. 插值、v-text、v-html
Vue的指令:v-
插值格式:
{{表达式}}
在网速较慢时,可能会出现原始的 {{}} ,加载完毕后才会显示正确数据。插值闪烁
v-text,v-html可以解决插值闪烁
还可以将数据输出到元素内部,如果有html代码,v-text普通文本输出,v-html会将html标签渲染。
单向绑定将数据输出到页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
{{msg}} <br>
v-text:<span v-text="msg"></span><br> <!-- 输出普通文本 -->
v-html:<span v-html="msg"></span><br> <!-- 输出渲染后的html -->
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
msg:"<h2>Vue</h2>"
}
});
</script>
</body>
</html>
5.指令 v-model
双向绑定:视图和模型中数据相互影响
可使用的元素有:
- input
- select:定义下拉列表
- textarea:多行的文本输入
- checkbox:复选框
- radio:单选
- components(vue中的自定义组件)
- 多个 checkbox 对应一个model时,model的类型是一个数组,单个checkbox值是boolean类型
- radio对应的值是input的value值
- input 和 textarea 默认对应的model是字符串
- select单选对应字符串,多选对应也是数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<input type="checkbox" value="0" v-model="lag">0<br>
<input type="checkbox" value="1" v-model="lag">1<br>
<input type="checkbox" value="2" v-model="lag">2<br>
<input type="radio" value="4" v-model="rad">4<br>
{{lag.join(",")}}
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
lag:[],
}
});
</script>
</body>
</html>
6.指令 v-on
页面元素绑定事件
格式:
v-on:事件名="js片段或函数名"
v-on:click='add'
@事件名="js片段或函数名"
@click='add'
事件修饰符:
- .stop :阻止事件冒泡
- .prevent :阻止默认事件发生
- .capture :使用事件捕获模式
- .self :只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
- .once :只执行一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<button v-on:click="num++">增加</button>
<button @click="dec">减少</button>
num = {{num}} <br>
事件冒泡测试<br>
<!--在点击button是,也会父事件点击div,但只想输出点击button,不执行父事件,通过事件修饰符-->
<div style="background-color: lightgreen; width: 100px; height: 100px;" @click="print('div被点击')">
<button @click.stop="print('button被点击')">点我</button>
</div>
<br>阻止默认事件的发生--事件修饰符 不会进行跳转了<br>
<div>
<a href="https://www.baidu.com" @click.prevent="print('点击了超链接')">百度</a>
</div>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
num:1
},
methods:{
//递减
dec(){
this.num--;
},
//打印
print(str){
console.log(str);
}
}
});
</script>
</body>
</html>
7.指令v-for使用
数组、对象遍历
可以在vue实例化的时候指定要遍历的数据,通过v-for在模板中遍历显示数据。一般情况下,要遍历的数据可以通过钩子函数created发送异步请求获取数据
格式:
//遍历数组
v-for="item in items"
v-for="(user, index) in users" //index索引号
//遍历对象
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<ul> <!--无序列表标签-->
<li v-for="(user,index) in users"> <!--index索引号-->
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
</li>
</ul>
<hr>
<ul>
<li v-for="(value,key,index) in person">
{{index}}--{{key}}--{{value}}
</li>
</ul>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
users:[
{"name":"张三","age":10,"gender":"男"},
{"name":"李四","age":11,"gender":"女"},
{"name":"王五","age":12,"gender":"男"}
],
person:{"name":"对象","addres":"上海","age":20}
}
});
</script>
</body>
</html>
key是唯一标识,key一般使用在遍历完后,又增、减集合元素
<ul><li v-for="(item,index) in items" :key="index"></li> </ul>
8.指令v-if 和 v-show使用
通过判断实现内容的隐藏
格式:
v-if="布尔表达式"
v-show="布尔表达式"
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-if在条件不满足时,元素不存在
v-show条件不满足时,只是对条件进行隐藏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<button @click="show=!show">点击</button>
<!-- v-if-->
<h2 v-if="show">
Vue!
</h2>
<hr>
<!-- v-if v-else-->
<ul>
<li v-for="(user,index) in users" v-if="user.gender=='男'" style="background-color: lightgreen">
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
</li>
<li v-else style="background-color: red">
{{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
</li>
</ul>
<hr>
<!-- v-show-->
<h2 v-show="show">
v-show
</h2>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true,
users:[
{"name":"张三","age":10,"gender":"男"},
{"name":"李四","age":11,"gender":"男"},
{"name":"王五","age":12,"gender":"女"}
]
}
});
</script>
</body>
</html>
9.指令v-bind
在元素的属性上使用vue实例的数据
<img src=" " height=" " />
如果src和height属性不想写死,而是通过获取vue实例中数据属性值,使用v-bind
格式:
<img v-bind:src="vue实例中数据属性名" :height="vue实例中数据属性名" />
可以直接 : 简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
<style type="text/css">
div{
width: 100px;
height: 100px;
color: yellow;
}
.red{
background-color: red;
}
.green{
background-color: green;
}
</style>
</head>
<body>
<div id="app">
<button @click="color='red'">红色</button>
<button @click="color='green'">绿色</button>
<div :class="color">
v-bind: 简写 :
</div>
<hr>
<button @click="bool=!bool">切换颜色</button>
<div :class="{red:bool,green:!bool}">
clss属性的特殊用法
</div>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
color:"red",
bool:true
}
});
</script>
</body>
</html>
10.计算属性
日期的毫秒值进行格式化(yyyy-MM-dd)字符串,使用computed计算属性中的方法进行处理
计算属性的方法必须有返回值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<h2>
日期为:{{day}}
</h2>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
daynum:2429032123201
},
computed:{
day(){
const d = new Date(this.daynum);
return d.getFullYear() +"-"+(d.getMonth()+1)+"-"+d.getDay();
}
}
});
</script>
</body>
</html>
可以用在插值或制定表达式复杂的时候,可以把属性数据经过方法处理之后返回
11.watch基本和深度监控
vue实例中数据属性,在页面中修改而产生了变化,可以通过watch监控获取改变前后的值
如果修改的是对象属性,可以开启深度监控获取修改后最新的对象数据。如;person.name
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<hr>
<input type="text" v-model="person.name">
<hr>
<input type="text" v-model="person.age"><button @click="person.age++">+</button>
<br>
<h2>
姓名:{{person.name}};年龄:{{person.age}}
</h2>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
message:"0",
person:{"name":"lisi","age":13}
},
watch:{
//监控数据属性
message(oldVlue,newVlue){ //监控变量的方法名要和数据属性变量名一致
console.log("new:"+newVlue);
console.log("old:"+oldVlue);
},
//对象监控
person: { //与对象属性名一致
//需开启深度监控:监控对象属性变化
deep:true,
//handler方法 obj可以获取到最新属性数据
handler(obj){
console.log("name:"+obj.name + " age:" + obj.age);
}
}
}
});
</script>
</body>
</html>
watch使用场景:可以监视视图中数据变化而做出响应。如:下拉框列表中,选择了对应的下拉框选项之后,要根据最新的值去加载一些其他数据。
12.组件
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部
导航。
但是如果每个页面都独自开发,这无疑增加了开发的成本。所以会把页面的不同部分拆分成独立的组件,然后在不同
页面就可以共享这些组件,避免重复开发。
组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等。
全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
data的定义方式比较特殊,必须是一个函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<!-- //使用组件-->
<counter></counter>
</div>
<script type="text/javascript">
//定义组件
const count = {
template:"<button @click='num++'>点击{{num}}次</button>", //模板
data(){ //data定义方式是一个函数
return {num:0}
}
};
//全局注册组件:在所有vue实例中都可以使用
//参数1:组件名 参数2:具体组件
//Vue.component("counter",count);
var app = new Vue({
el:"#app",
//局部注册 //这个counter组件只能在当前的Vue实例中使用
components:{
counter:count
}
});
</script>
</body>
</html>
全局注册:在所有vue实例中都可以使用。eg:头部导航菜单
局部注册:组件只能在当前的Vue实例中使用
13.父组件向子组件通信
各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。
传递普通字符串:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<introduce :title="msg"></introduce>
</div>
<script type="text/javascript">
//定义组件
const introduce = {
template: "<h2>{{title}}</h2>>",
//定义接收父组件的属性
props:["title"]
};
//全局注册组件
Vue.component("introduce",introduce);
var app = new Vue({
el:"#app",
data:{
msg:"父组件的msg内容"
}
});
</script>
</body>
</html>
传递数组或者对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<!--定义的组件myList有大写字母-->
<my-list :items="lessons"></my-list>
</div>
<script type="text/javascript">
//定义组件
const myList = {
template:`
<ul>
<li v-for="item in items" :key="item.id">{{item.id}}--{{item.name}}</li>
</ul>`,
//定义接收父组件的属性
props:{
items:{
//数据类型:数组-Array;对象--Object
type:Array,
default:[]
}
}
};
var app = new Vue({
el:"#app",
data:{
msg:"父组件msg属性数据",
lessons:[
{"id":1,"name":"lisi"},
{"id":2,"name":"zs"},
{"id":3,"name":"ww"}
]
},
components:{
myList //组件名和定义的名称一样可简写
}
});
</script>
</body>
</html>
default,如果是对象则需要写成方法的方式返回默认值。如:
default(){
return {"xxx":"默认值"};
}
14.子组件向父组件通信
点击按钮改变父组件中的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子组件向父组件通信</title>
<script src="vue/vue-2.6.10.js"></script>
</head>
<body>
<div id="app">
<counter @plus="numPlus" @reduce="numReduce" :snum="num"></counter>
<h2>{{num}}</h2>
</div>
<script type="text/javascript">
//定义组件
const counter = {
<!--只能有一个根元素,所以用 div对其进行包裹-->
template:`
<div>
<button @click="incrnum">+</button>
<button @click="decrnum">-</button>
</div>
`,
props:["snum"],
methods: {
incrnum(){
//调用父组件中的方法
return this.$emit("plus"); //有数据需要接受的话 this.$emit("plus",123); 相应的定义方法中要有形参
},
decrnum(){
return this.$emit("reduce");
}
}
};
var app = new Vue({
el:"#app",
data:{
num:0
},
components:{
counter
},
methods:{
numPlus(){
this.num++;
},
numReduce(){
this.num--;
}
}
});
</script>
</body>
</html>
15.axios
发送异步请求获取数据,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue/vue-2.6.10.js"></script>
<script src="vue/axios.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="user in users">{{user.id}}--{{user.name}}</li>
</ul>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data: {
users:[]
},
create(){
//钩子函数,初始化数据
axios.get("data.json").then(res=>{
console.log(res);
app.users = res.date; //在axios回调函数中不能用 this,表示窗口
}).catch(err=>alert(err));
}
});
</script>
</body>
</html>
注意:如果不是一个服务器可能会出现跨域请求
跨域:在前端js中发送异步请求,请求的地址与当前服务器ip或者端口号不同都是跨域请求,在服务器端配置@CrossOrigin