一.Vue.js
1.1 Vue.js是什么?
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是, Vue 被设计 为可以自底向上逐层应用.
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一 方面,当与 现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
1.2 为什么使用Vue?
- 声明式渲染: 前后端分离是未来趋势
- 渐进式框架: 适用于各种业务需求
- 简单易学: 国人开发,中文文档,不存在语言障碍,易于理解和学习
二.Vue.js 基础
2.1 ## 引入Vue.js库
想使用Vue需要在html界面载入Vue.js的库,两种方式:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 1.引入vue.js -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> -->
<script src ="js/vue.min.js"></script>
2.2 插件的安装
2.3 data存储复杂数据
使用data存储复杂数据:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 1.引入vue.js -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> -->
<script src ="js/vue.min.js"></script>
</head>
<body>
<!-- 2.创建ID为APP的Div -->
<div id ="app">
{{name}}<br>
{{school.name}} {{school.mobile}}<br>
<ul>
<li>{{names[0]}}</li>
<li>{{names[1]}}</li>
<li>{{names[2]}}</li>
</ul>
</div>
<div>
{{name}}
</div>
</body>
<script>
//3.创建vue实例
var VM = new Vue({
el:"#app",
data:{
name:"Hello Vue!!",
//对象类型
school:{
name:"拉钩教育",
mobile:"1001001",
},
//数组类型
names:["尼古拉斯","赵四","凯撒"]
},
{{}}: 插值表达式 插值表达式的作用?
通常用来获取Vue实例中定义的数据(data)
属性节点中 不能够使用插值表达式
el: 挂载点
el的作用?
定义 Vue实例挂载的元素节点,表示vue接管该区域
Vue的作用范围是什么 ?
Vue会管理el选项命中的元素,及其内部元素
el选择挂载点时,是否可以使用其他选择器 ?
可以,但是建议使用 ID选择器
是否可以设置其他的DOM元素进行关联 ?
可以但是建议选择DIV, 不能使用HTML和Body标签
2.4 声明式渲染的好处
Vue中的声明式渲染,简单理解就是我们声明数据,Vue帮我们将数据渲染到HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h2>{{name}}</h2>
</div>
</body>
<!-- <script src = "js/jquery-1.8.3.min.js"></script>
<script>
$(document).ready(function(){
$("#app").append("<h2>Hello Wrold</h2>");
});
</script> -->
<script src ="js/vue.min.js"></script>
<script>
var VM =new Vue({
el:"#app", //挂载点
data:{
name:"Hello Wrold!"
},
});
</script>
</html>
不使用声明式渲染的话 需要拼接数据输出
使用声明式渲染 就可以直接把数据使用插值表达式输出
2.5 Vue常用指令
根据官网的介绍,指令 是带有 v- 前缀的特殊属性。通过指令来操作DOM元素
(1) v-text 指令
作用: 获取data数据, 设置标签的内容.
注意: 默认写法会替换全部内容,使用插值表达式{{}}可以替换指定内容. 代码示例:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id = "app">
<h2>{{message}}高薪训练营</h2>
<!-- v-text 获取data数据,设置标签内容-->
<h2 v-text = "message">高薪训练营</h2>
<!-- 拼接字符串 -->
<h2 v-text="message+1"></h2>
<h2 v-text="message+'abc'"></h2>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data: {
message:"Java程序员",
},
});
</script>
</html>
(3)v-html指令
v-html 指令;设置元素的innerHTML,向元素中写入标签
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/*
v-html 指令;设置元素的innerHTML,向元素中写入标签
*/
</style>
</head>
<body>
<div id="app">
{{message}}
<h2 v-text = "message"></h2>
<h2 v-html = "message"></h2>
<h2 v-html = "url"></h2>
<h2 v-text = "url"></h2>
<!-- 设置元素的innerHTML -->
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
message:"Java程序员",
url:"<a href='https://www.baidu.com'>百度一下</a>"
},
});
</script>
</html>
v-html可以设置元素的innerHTML,但v-text不可以,v-text会把原本的代码输出出来。
(3)v-on指令
作用: 为元素绑定事件, 比如: v-on:click,可以简写为 @click="方法" 绑定的方法定义在 VUE实例的, method属性中
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style >
/*
v-on指令:作用是为1元素绑定事件
*/
</style>
</head>
<body>
<div id ="app">
<input type="button" value ="点击按钮" v-on:click="show" />
<!-- 简写方式 -->
<input type="button" value ="点击按钮" @click="show" />
<!-- 绑定双击事件 -->
<input type="button" value ="双击按钮" @dblclick="show" />
<!-- 绑定事件,点击后修改当前内容 -->
<h2 @click="changeFood">{{food}}</h2>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
food:"麻辣小龙虾"
},
//通过methods专门存放Vue的方法
methods:{
show:function(){
alert("程序员在加班!!");
},
changeFood:function(){
console.log(this.food); //保存
//使用this获取data中的数据
//在vue中不需要考虑如何更改DOM,重点放在修改数据上,数据更新后,使用数据的那个元素也会同步更新
this.food+="真好吃";
},
},
});
一直点的话字体会一直增加
(4)计数器案例
首先准备页面
<div id="app">
<!-- 计算功能区域 -->
<div>
<input type="button" class="btn btn_plus">
<span>{{num}}</span>
<input type="button" class="btn btn_minus">
</div>
</div>
</body>
<script src="vue.min.js"></script>
<script>
//创建VUE实例
var VM = new Vue({
el:"#app",
data:{
num:1
}
})
</script>
全部代码;
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="css/inputNum.css" />
</head>
<body>
<div id="app">
<!-- 计算功能区域 -->
<div>
<input type="button" class = "btn btn_plus" v-on:click="add"/>
<span>{{num}}</span>
<input type="button" class = "btn btn_minus" @click="sub"/>
</div>
</div>
</body>
<script src = "js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
num : 1,
},
methods:{
add:function(){
if(this.num < 10){
this.num++;
}else{
alert("别点了");
}
},
sub:function(){
if(this.num > 0){
this.num--;
}else{
alert("最小了");
}
}
}
});
</script>
</html>
(5)v-show指令
作用: v-show指令, 根据真假值,切换元素的显示状态 页面准备:
<div id="app">
<img src="./img/car.gif" alt="">
</div>
</body>
<script src="vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app"
})
</script>
代码示例:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/*
v-show:根据真假值,切换元素的显示状态
*/
</style>
</head>
<body>
<div id="app">
<img v-show = "isShow" src="img/loading.gif" />
<input type="button" value="切换状态" @click="changeShow" />
<img v-show="age > 18" src ="img/loading.gif" />
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
isShow:false,
age:19,
},
methods:{
changeShow:function(){
//触发方法,对isShow进行取反
this.isShow=!this.isShow;
}
}
});
</script>
</html>
三种方式:isShow的值改成true或者flase直接输出
写方法对isShow取反输出
以及直接在<img>里写判断输出
(6) v-if 指令
作用: 根据表达值的真假,切换元素的显示和隐藏( 操纵dom 元素)
代码示例:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/*
v-if指令:根据表达式的真假,切换元素的显示和隐藏(操作的是dom)
频繁切换就是用v-show,
反之使用v-if
*/
</style>
</head>
<body>
<div id="app">
<input type="button" value = "切换状态" @click="changeShow">
<img v-if="isShow" src="img/loading.gif">
</div>
</body>
<script src = "js/vue.min.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
isShow:false
},
methods:{
changeShow:function(){
this.isShow=!this.isShow;
},
},
});
</script>
</html>
频繁切换就是用v-show,
反之使用v-if
(7) v-bind 指令
作用: 设置元素的属性 (比如:src,title,class)
语法格式: v-bind:属性名=表达式
<img v-bind:src="imgSrc">
var VM = new Vue({
el:"#app",
data:{
imgSrc:"图片地址"
}
})
v-bind 可以省略,简写为冒号 :
<img :src="imgSrc">
代码示例:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
v-bind : 设置元素的属性 src class
语法: v-bind:属性名=表达式
作用: 为元素绑定属性
完整写法: v-bind:属性名 = 表达式 ,简写 :属性=表达式
*/
</style>
</head>
<body>
<div id="app">
<img src="img/loading.gif" alt="" />
<!-- 使用 v-bind 设置src属性 -->
<img v-bind:src="imgSrc" />
<!-- v-bind 可以简写为 : -->
<img v-bind:src="imgSrc" :title="imgTitle" />
<!-- 设置class -->
<div :style="{ fontSize: size+'px' }">v-bind指令</div>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
imgSrc: "img/loading.gif",
imgTitle: "拉钩教育",
size: 50,
},
});
</script>
</html>
(8) v-for 指令
作用: 根据数据生成列表结构
数组经常和 v-for结合使用,数组有两个常用方法: push() 向数组末尾添加一个或多个元素
shift() 把数组中的第一个元素删除
语法是: (item,index) in 数据
item和index 可以结合其他指令一起使用
数组的长度变化,会同步更新到页面上,是响应式的
代码示例:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
v-for指令:根据数据生成列表结构
1.数组经常和v-for结合使用
2.语法格式: (item,index) in 数据
3.数组的长度变化,会同步更新到页面上, 响应式的
*/
</style>
</head>
<body>
<div id="app">
<input type="button" value="添加数据" @click="add" />
<input type="button" value="移除数据" @click="remove" />
<ul>
<!-- 在li标签中 获取数组的元素 -->
<li v-for="(item,index) in arr">
{{index+1}}城市: {{item}}
</li>
</ul>
<!-- 使用h2标签显示
-->
<h2 v-for="p in persons">
{{p.name}}
</h2>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
//数组
arr: ["上海", "北京", "广东", "深圳"],
//对象数组
persons: [
{ name: "尼古拉斯·赵四" },
{ name: "莱昂纳多·小沈阳" },
{ name: "多利安·刘能" },
],
},
methods: {
add: function () {
//向数组添加元素 push
this.persons.push({ name: "小斌" });
},
remove: function () {
//移除数据
this.persons.shift();
},
},
});
</script>
</html>
(9) v-on 指令补充
- 传递自定义参数 : 函数调用传参
- 事件修饰符: 对事件触发的方式进行限制
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
1.函数调用传参
事件绑定方法后,可以传递参数
定义方法时,需要定义形参,来接收参数
2.事件修饰符
可以对事件进行限制, .修饰符
.enter 可以限制触发的方式为 回车
*/
</style>
</head>
<body>
<div id="app">
<!-- 函数传参 -->
<input
type="button"
value="礼物刷起来"
@click="showTime(666,'爱你老铁!')"
/>
<!-- 事件修饰符 指定哪些方式可以触发事件 -->
<input type="text" @keyup.enter="hi" />
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {},
methods: {
showTime: function (p1, p2) {
console.log(p1);
console.log(p2);
},
hi: function () {
alert("你好吗?");
},
},
});
</script>
</html>
(10).MVVM模式
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式.
MVVM模式将页面分成了 M 、V、和VM ,解释为:
Model: 负责数据存储 ------ View: 负责页面展示 ------View Model: 负责业务逻辑处理(比如Ajax请求等),对数据进行加工后交给视图展示
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如 果有变化,则更改Model中的数据;
从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的 DOM元素
(11).v-mode 指令
作用: 获取和设置表单元素的值(实现双向数据绑定)
单向绑定: 就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动 更新。
双向绑定: 用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。
什么情况下用户可以更新View呢?
填写表单就是一个最直接的例子。当用户填写表单时,View的状态就被更新了,如果此时 MVVM框架可以自动更新Model的状态,那就相当于我们把Model和View做了双向绑定:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
v-model: 实现双向数据绑定
单向数据绑定: 将model绑定到view上,当model发生变化时,view会随之变化
双向数据绑定: view视图发生变化时,model也会随之改变
*/
</style>
</head>
<body>
<div id="app">
<input type="button" value="修改message" @click="update" />
<!-- View 视图 -->
<!-- <input type="text" v-bind:value="message" /> -->
<!-- v-model 实现双向数据绑定 -->
<input type="text" v-model="message" />
<input type="text" v-model="password" />
<h2>{{message}}</h2>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
//VM 业务逻辑控制
var VM = new Vue({
el: "#app",
//Model 数据存储
data: {
message: "拉钩教育训练营",
password: 123,
},
methods: {
update: function () {
this.message = "拉钩";
},
},
});
</script>
</html>
(12) 实现简单记事本
实现一个如图所示的记事本 输入框用来对记事本添加文本,左下角显示当前记事本文本数,右下角删除当前记事本所有内容.
代码示例:
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>小黑记事本</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="googlebot" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="../css/index.css" />
</head>
<body>
<!-- VUE示例接管区域 -->
<section id="app">
<!-- 输入框 -->
<header class="header">
<h1>VUE记事本</h1>
<input
autofocus="autofocus"
autocomplete="off"
placeholder="输入日程"
class="new-todo"
v-model="inputValue"
@keyup.enter="add"
/>
</header>
<!-- 1.使用v-for指令生成列表结构 -->
<!-- 列表区域 -->
<section class="main">
<ul class="listview">
<li class="todo" v-for = "(item,index) in list">
<div class="view">
<span class="index">{{index+1}}</span> <label>{{item}}</label>
<!-- 2.删除操作 传递index -->
<button class="destroy" @click = "remove(index)"></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<footer class="footer">
<span class="todo-count"> <strong>{{list.length}}</strong> items left </span>
<button class="clear-completed" @click="clear">
Clear
</button>
</footer>
</section>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var VM = new Vue({
el:"#app",
data:{
list:["写代码","吃饭","睡觉"],
inputValue:"996还是997",
},
methods:{
//新增日程
add:function(){
//将用户输入的内容添加到list
this.list.push(this.inputValue);
},
remove:function(index){
console.log(index);
//使用 splice(接收两个参数:元素的索引,删除几个对象)
this.list.splice(index,1); // index为元素索引 1为删除对象
},
//清空操作
clear:function(){
this.list=[];
}
},
});
</script>
</body>
</html>
三.axios
3.1 Ajax回顾
Ajax 是指一种创建交互式网页应用的开发技术。Ajax = 异步 JavaScript 和 XML。
Ajax的作用
Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分 进行更新(局部更新)。传统的网页如果需要更新内容,必须重载整个网页页面。
简单记: Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术, 维护用户体验 性, 进行网页的局部刷新.
异步与同步: 浏览器访问服务器的方式
同步访问: 客户端必须等待服务器端的响应,在等待过程中不能进行其他操作 。
异步访问: 客户端不需要等待服务的响应,在等待期间,浏览器可以进行其他操作。
Ajax案例演示:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" />
<input type="button" value="Jquery发送异步请求" onclick="run1()" />
</body>
<script src="./js/jquery-1.8.3.min.js"></script>
<script>
function run1() {
$.ajax({
url: "http://localhost:8080/ajax",
async:true,
data: { name: "天青" },
type: "post",
success: function () {
alert("响应成功");
},
error: function () {
alert("响应失败!");
},
});
}
</script>
</html>
Java中的Servlet文件
public class AjaxServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//1.获取请求数据
String username = req.getParameter("name");
//模拟业务操作,造成的延时效果
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.打印username
System.out.println(username);
resp.getWriter().write("hello hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
3.2 axios介绍
axios是目前十分流行网络请求库,专门用来发送请求,其内部还是ajax,进行封装之后使用更加方便
axios作用: 在浏览器中可以帮助我们完成 ajax异步请求的发送.
axios使用步骤:
1.导包
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2.请求方式:
以GET和POST举例
测试一下axios,我们设置两个接口
接口1(笑话接口):
请求地址:https://autumnfish.cn/api/joke/list
请求方法:get
请求参数:num(笑话条数,数字)
响应内容:随机笑话
接口2(用户注册):
请求地址:https://autumnfish.cn/api/user/reg
请求方法:post
请求参数:username(用户名,字符串)
响应内容:注册成功或失败
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
axios总结
1.axios必须要导包
2.使用get或者post方式发送请求
3.then方法 中的回调函数,会在请求成功或者失败的时候被触发
4.通过回调函数的形参,可以获取响应的内容
*/
</style>
</head>
<body>
<input type="button" value="get请求" id="get" />
<input type="button" value="post请求" id="post" />
</body>
<script src="js/axios.min.js"></script>
<script>
/*
随机笑话接口测试
请求地址:https://autumnfish.cn/api/joke/list
请求方法:get
请求参数:num(笑话条数,数字)
响应内容:随机笑话
*/
document.getElementById("get").onclick = function () {
axios.get("https://autumnfish.cn/api/joke/list?num=1").then(
function (resp) {
//调用成功
console.log(resp);
},
function (err) {
//调用失败
console.log(err);
}
);
};
/*
用户注册
请求地址:https://autumnfish.cn/api/user/reg
请求方法:post
请求参数:username:"用户名"
响应内容:注册成功或失败
*/
document.getElementById("post").onclick = function () {
axios.post("https://autumnfish.cn/api/user/reg", { username: "张abc" }).then(
function (resp) {
console.log(resp);
},
function (error) {
console.log(error);
}
);
};
</script>
</html>
axios总结:
- 首先必须导包才能使用
- 使用get或者post方法 发送请求
- then方法中的回调函数,会在请求成功或请求失败时触发
- 通过回调函数的形参可以获取响应的内容,或者错误信息
3.3 获取笑话案例
通过vue+axios 完成一个获取笑话的案例.
接口: 随机获取一条笑话
请求地址:https://autumnfish.cn/api/joke
请求方法:get
请求参数:无
响应内容:随机笑话
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vue+axios获取笑话</title>
<style>
/*
1.axios回调函数中,this的指向已经改变,无法访问data中的数据
2.解决方案: 将this进行保存
*/
</style>
</head>
<body>
<div id="app">
<input type="button" value="点击获取一个笑话" @click="getJoke" />
<p>{{joke}}</p>
</div>
</body>
<script src="../js/vue.min.js"></script>
<script src="../js/axios.min.js"></script>
<script>
/*
请求地址:https://autumnfish.cn/api/joke
请求方法:get
请求参数:无
响应内容:随机笑话
*/
var VM = new Vue({
el: "#app",
data: {
joke: "笑口常开",
},
methods: {
getJoke: function () {
//把this进行保存
var that = this;
//异步访问
axios.get("https://autumnfish.cn/api/joke").then(
function (resp) {
console.log(resp.data);
//在回调函数内部 ,this无法正常使用,需要提前保存起来
console.log(that.joke); //undefined
that.joke = resp.data;
},
function (error) {}
);
},
},
});
</script>
</html>
3.4 天气查询案例
功能分析:
回车查询
1.输入内容,点击回车 (v-on.enter)
2.访问接口,查询数据 (axios v-model)
3.返回数据,渲染数据
接口文档
需要额外的写一个自己的js文件,在main.js写方法
作为一个标准的应用程序,我们将创建VUE实例的代码,抽取到main.js 文件中
main.js
/**
*
* 请求地址:http://wthrcdn.etouch.cn/weather_mini
请求方法:get
请求参数:city (要查询的城市名称)
响应内容:天气信息
*/
var VM = new Vue({
el: "#app",
data: {
city: "",
//定义数组保存 天气信息
weatherList: [],
},
//编写查询天气的方法
methods: {
searchWeather: function () {
console.log("天气查询");
console.log(this.city);
var that = this;
//调用接口
axios.get("http://wthrcdn.etouch.cn/weather_mini?city=" + this.city).then(
function (resp) {
console.log(resp.data.data.forecast);
//获取天气信息 保存到weatherList
that.weatherList = resp.data.data.forecast;
},
function (error) {}
);
},
},
});
主体
<body>
<div class="wrap" id="app" v-cloak>
<div class="search_form">
<div class="logo">天气查询</div>
<div class="form_group">
<input
type="text"
class="input_txt"
placeholder="请输入要查询的城市"
v-model="city"
@keyup.enter="searchWeather"
/>
<button class="input_sub">回车查询</button>
</div>
</div>
<ul class="weather_list">
<!-- 展示数据 -->
<li v-for="item in weatherList">
<div class="info_type">
<span class="iconfont">{{item.type}}</span>
</div>
<div class="info_temp">
<b>{{item.low}}</b>
~
<b>{{item.high}}</b>
</div>
<div class="info_date"><span>{{item.date}}</span></div>
</li>
</ul>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 自己的js -->
<script src="./js/main.js"></script>
</body>
天气案例总结
- 应用的逻辑代码,建议与页面进行分离,使用单独的JS编写
- axios回调函数中的 this的指向改变,无法正常使用, 需要另外保存一份
- 服务器返回的数据比较的复杂时,获取数据时要注意层级结构
解决BUG:页面闪烁问题
v-cloak指令
作用: 解决插值表达式闪烁问题
当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码。我 们可以使用 v-cloak 指令来解决这一问题。
<style>
/* 通过属性选择器,设置 添加了v-cloak */
[v-cloak] {
display: none;
}
</style>
然后在id为"app"的div中写下:
<div class="wrap" id="app" v-cloak>
四.Vue进阶
4.1 computed 计算属性
什么是计算属性 在Vue应用中,在模板中双向绑定一些数据或者表达式,但是表达式如果过长,或者逻辑更为复杂 时,就会变得臃肿甚至难以维护和阅读,比如下面的代码:
写在双括号中的表达式太长了,不利于阅读 {{text.split(',').reverse().join(',')}}
.将这段操作text.split(',').reverse().join(',') 放到计算属性中,最终返回一个结果值就可以
computed 的作用: 减少运算次数, 缓存运算结果. 运用于重复相同的计算
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=<device-width>, initial-scale=1.0" />
<title>Document</title>
<style>
/*
1.计算属性可以 减少运算次数,用于重复相同的计算
2.定义函数也可以实现与计算属性相同的效果,但是计算属性可以简化运算
*/
</style>
</head>
<body>
<div id="app">
<!-- <h1>{{a*b}}</h1>
<h1>{{a*b}}</h1> -->
<!--
<h1>{{res()}}</h1>
<h1>{{res()}}</h1> -->
<h1>{{res2}}</h1>
<h1>{{res2}}</h1>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
a: 10,
b: 20,
},
methods: {
res: function () {
console.log("res方法执行了! !");
return this.a + this.b;
},
},
//使用计算属性 进行优化,减少运算次数,用于重复的运算
computed: {
res2: function () {
console.log("res2方法执行了! !");
return this.a + this.b;
},
},
});
</script>
</html>
computed总结
定义函数也可以实现与 计算属性相同的效果,都可以简化运算。
不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会 重新求值。
4.2 filter 过滤器
什么是过滤器:
过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原 来的数据,只是在原数据的基础上产生新的数据。
Vue中过滤器分为全局过滤器和局部过滤器
过滤器的使用位置:
1.插值表达式内:
{{ msg | filterA }} msg是需要处理的数据, filterA是过滤器, | 这个竖线是管道,通过这个管道
将数据传输给过滤器进行过滤 加工操作
- v-bind里:
<h1 v-bind:id=" msg | filterA"> {{ msg }} </h1>
(1)全局过滤器:
全局过滤器只需要把过滤器的表达式放在创建Vue实例的语句前就会形成全局过滤
需求: 将用户名开头字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/*
需求: 将用户名开头字母大写
总结:
1.过滤器经常被用来处理文本格式化操作
2.过滤器使用的两个位置: {{}} 插值表达式中, v-bind表达式中
3.过滤器是通过管道传输数据的 |
*/
</style>
</head>
<body>
<div id="app">
<p>{{user.name | changeName}}</p>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
//在创建vue实例之前,创建全局过滤器
Vue.filter("changeName", function (value) {
//将姓名的开头字母大写
return value.charAt(0).toUpperCase() + value.slice(1);
});
var VM = new Vue({
el: "#app",
data: {
user: { name: "jack" },
},
});
</script>
</html>
(2)局部过滤器:
局部过滤需要把过滤器的表达式放在Vue实例里面
需求:将用户名开头字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用插值表达式,调用过滤器 -->
<p>电脑价格: {{price | addIcon}}</p>
<h1 v-bind:id=" msg | filterA"> {{ msg }} </h1>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
//局部过滤器 在vue实例的内部创建filter
var VM = new Vue({
el: "#app", //挂载点
data: {
//model
price: 200,
},
methods: {
//方法
},
computed: {
//计算属性
},
//局部过滤器
filters: {
//定义处理函数 value = price
addIcon(value) {
return "$" + value;
},
},
});
</script>
</html>
过滤器总结:
-
过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
-
过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示
4.3 监听器
什么是监听器
Vue.js 提供了一个方法 watch,它用于观察Vue实例上的数据变动。
作用: 当你有一些数据需要随着其它数据变动而变动时,可以使用侦听属性
案例展示;
(实时显示姓名)
在文本框里输入时 在文本框右边会同步显示 这就是监听器的作用:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<label>名:<input type="text" v-model="fristName" /></label>
<label>姓:<input type="text" v-model="lastName" /></label>
{{fullName}}
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
fristName: "",
lastName: "",
fullName: "",
},
//侦听器
watch: {
fristName: function (nval, oval) {
//参数 1.新值,2.旧值
this.fullName = nval + " " + this.lastName;
},
lastName: function (nval, oval) {
this.fullName = this.fristName + " " + nval;
},
},
});
</script>
</html>
4.4 Component组件
组件(Component)是自定义封装的功能。在前端开发过程中,经常出现多个网页的功能是重复 的,而且很多不同的页面之间,也存在同样的功能。
我们将相同的功能进行抽取,封装为组件,这样,前端人员就可以在组件化开发时,只需要书写一次代 码,随处引入即可使用。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象 为一个组件树
vue的组件有两种: 全局组件 和 局部组件
全局组件:
语法格式:
写在Vue实例外面
组件的命名规则: 一般用短横线进行连接,左边是公司名 右边组件的作用名称
Vue.component("组件名称", {
template: "html代码", // 组件的HTML结构代码
data(){ //组件数据
return {}
},
methods: { // 组件的相关的js方法
方法名(){
// 逻辑代码
}
}
})
注意:
- 组件名以小写开头,采用短横线分割命名: 例如 hello-Word
- 组件中的data 必须是一个函数,注意与Vue实例中的data区分
- 在template模板中, 只能有一个根元素
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用组件 -->
<lagou-header></lagou-header>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
//定义全局组件
//组件的命名规则: 一般用短横线进行连接,左边是公司名 右边组件的作用名称
Vue.component("lagou-header", {
template: "<div>HTML <h1 @click='hello'>{{msg}}</h1> </div>", //template模板中 只能有一个根元素
//组件中的data是一个函数
data() {
return {
msg: "这lagou-header是组件中的数据部分",
};
},
methods: {
hello() {
alert("你好");
},
},
});
var VM = new Vue({
el: "#app",
data: {},
methods: {},
});
</script>
</html>
局部组件:
相比起全局组件,局部组件只能在同一个实例内才能被调用。局部组件的写法和全局组件差不多。 唯一不同就是:局部组件要写在Vue实例里面。
语法格式:
new Vue({
el: "#app",
components: {
组件名: {
// 组件结构
template: "HTML代码",
// data数据
data() { return { msg:"xxxx" };},
},
},
});
注意: 创建局部组件,注意 components,注意末尾有 ‘s’,而全局组件是不用+ ‘s’ 的。这意味着, components里可以创建多个组件
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<web-msg></web-msg>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
//创建局部组件
var VM = new Vue({
el:"#app",
components:{
//组件名
"web-msg":{
template:"<div><h1>{{msg1}}</h1><h1>{{msg2}}</h1></div>",
data() {
return {
msg1:"开发ing...",
msg2:"开发完成!"
}
},
}
}
})
</script>
</html>
4.5 组件与模板分离
由于把html语言写在组件里面很不方便,也不太好看所以将它们分开写。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 使用组件 -->
<web-msg></web-msg>
</div>
<!-- 将模板写在 HTML中,给模板一个id -->
<template id="t1">
<div>
<button @click="show">{{msg}}</button>
</div>
</template>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
components: {
"web-msg": {
template: "#t1",
data() {
return {
msg: "点击查询",
};
},
methods: {
show() {
alert("正在查询,请稍后...");
},
},
},
},
});
</script>
</html>
总结:
- 上面这种写法,浏览器会把 html 里的 template 标签过滤掉。所以 template 标签的内容是不会 在页面中展示的。直到它被 JS 中的 Vue 调用。
- 在 html 中,template 标签一定要有一个 id,因为通过 id 是最直接被选中的。 data 和 methods 等 参数,全部都要放到 Vue 实例里面写
五.Vue生命周期
每个Vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期
5.1 钩子函数介绍
生命周期中的钩子函数
钩子函数:钩子函数是在一个事件触发的时候,在系统级捕获到了他,然后做一些操作
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h2 id="msg">{{message}}</h2>
<button @click="next">获取下一句</button>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
message: "想当年,金戈铁马",
},
methods: {
show() {
alert("show方法执行了!");
},
next() {
this.message = "气吞万里如虎!";
},
},
// beforeCreate() {
// alert("1.beforeCreate函数,在Vue对象实例化之前执行");
// console.log(this.message); //undefined
// this.show(); //this.show is not a function
// },
// created() {
// alert("2.created函数执行时,组件的实例化完成,但是DOM页面还未生成")
// console.log(this.message);
// this.show();
// },
// beforeMount() {
// alert(
// "3.beforeMount函数执行时,模板已经在内存中编辑完成了,但是还没有被渲染到页面中"
// );
// console.log(
// "页面显示的内容" + document.getElementById("msg").innerText
// );
// console.log("data中的数据: " + this.message);
// },
// mounted() {
// alert("4.mounted函数执行时,模板已经被渲染到页面,执行完就会显示页面");
// console.log(
// "页面显示的内容" + document.getElementById("msg").innerText
// );
// },
// beforeUpdate() {
// alert("5.beforeUpdate执行时,内存中的数据已经更新,但是还没有渲染到页面");
// console.log(
// "页面显示的内容" + document.getElementById("msg").innerText
// );
// console.log("data中的数据: " + this.message);
// },
updated() {
alert("6.updated执行时,内存中的数据已经更新,此方法执行完显示页面");
console.log(
"页面显示的内容" + document.getElementById("msg").innerText
);
console.log("data中的数据: " + this.message);
},
});
</script>
</html>
六.Vue Router 路由
什么是路由?
在Web开发中,路由是指根据URL分配到对应的处理程序。 路由允许我们通过不同的 URL 访问不同的 内容。
通过 Vue.js 可以实现多视图单页面web应用(single page web application,SPA)
什么是SPA ?
单页面Web应用(single page web application,SPA),就是只有一张Web页面的应用, 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
单页应用不存在页面跳转,它本身只有一个HTML页面。我们传统意义上的页面跳转在单页应用的概 念下转变为了 body 内某些元素的替换和更新,举个例子
整个body的内容从登录组件变成了欢迎页组件, 从视觉上感受页面已经进行了跳转。但实际上,页面 只是随着用户操作,实现了局部内容更新,依然还是在index.html 页面中。
单页面应用的好处
- 用户操作体验好,用户不用刷新页面,整个交互过程都是通过Ajax来操作。
- 适合前后端分离开发,服务端提供http接口,前端请求http接口获取数据,使用JS进行客户端渲染
6.1 路由相关的概念
6.2 使用路由
Vue.js 路由需要载入 vue-router 库
//方式1: 本地导入
<script src="vue-router.min.js"></script>
//方式2: CDN
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
使用步骤
- 定义路由所需的组件
- 定义路由 每个路由都由两部分 path (路径) 和component (组件)
- 创建router路由器实例 ,管理路由
- 创建Vue实例, 注入路由对象, 使用$mount() 指定挂载点
Vue 的$mount()为手动挂载,在项目中可用于延时挂载(例如在挂载之前要进行一些其他操作、判断等), 之后要手动挂载上。new Vue时,el和$mount并没有本质上的不同。
HTML代码
<body>
<div id="app">
<h1>渣浪.com</h1>
<p>
<!-- 使用 router-link 组件来导航,to属性指定链接 -->
<router-link to="/home">go to home</router-link>
<router-link to="/news">go to news</router-link>
</p>
<!-- 路由的出口, 路由匹配到的组件(页面)将渲染在这里 -->
<router-view></router-view>
</div>
</body>
js代码:
<script src="./vue.min.js"></script>
<script src="./vue-router.min.js"></script>
<script>
//1.定义路由所需的组件
const home = { template: "<div>首页</div>" };
const news = { template: "<div>新闻</div>" };
//2.定义路由 每个路由都有两部分 path和component
const routes = [
{ path: "/home", component: home },
{ path: "/news", component: news },
];
//3.创建router路由器实例,对路由对象routes进行管理.
const router = new VueRouter({
routes: routes,
});
//4.创建Vue实例, 调用挂载mount函数,让整个应用都有路由功能
const VM = new Vue({
router,
}).$mount("#app"); //$mount是手动挂载代替el
</script>
运行结果:
未点击链接之前:
点击链接之后:
路由总结
- router是Vue中的路由管理器对象,用来管理路由.
- route是路由对象,一个路由就对应了一条访问路径,一组路由用routes表示
- 每个路由对象都有两部分 path(路径)和component (组件)
- router-link 是对a标签的封装,通过to属性指定连接
- router-view 路由访问到指定组件后,进行页面展示