Vue介绍
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架
与其它大型框架不同的是,Vue 被设计 为可以自底向上逐层应用
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合
另一 方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动
自底向上逐层应用:作为渐进式框架要实现的目标就是方便项目增量开发(即插即用)
官方网站: https://cn.vuejs.org/v2/guide/ 作者 尤雨溪是中国人
为甚么使用Vue:
声明式渲染:前后端分离是未来趋势
渐进式框架:适用于各种业务需求
简单易学:国人开发,中文文档,不存在语言障碍,易于理解和学习
Vue.js的使用:
Vue-CLI脚手架:使用vue.js官方提供的CLI脚本架很方便去创建vue.js工程雏形
vsCode插件
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7300ec11cfff263b23a09c6be718969c.png#pic_center)
上面括起来的,作用是,当你右键一下
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5a2de575d550ef31df1fd7fa5af9c577.png#pic_center)
出现Open with Live Server,打开,虽然也是打开一个浏览器,但是这个浏览器以端口来访问这个资源,一般是5000端口
我们每次保存一下在这个端口的网页文件时,他都会重新请求,相当于保存一下,刷新页面,而其他的插件作用自己去测试,这里就不多说了,一般ctrl+shift+p可以使用插件的一些命令,其实就是调出用于执行命令的输入框,这些命令通常来自VSCode已经使用或者说现在自带(一般不包括禁用的或者卸载的)当前有的插件扩展的命令,自己可以去看一看(禁用代表还在,但不使用,可以解除使用,但他存在,卸载代表不在了,不使用,可以安装后使用)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./js/vue.min.js"></script>
</head>
<body>
<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>
</body>
<script>
var VM = new Vue({
el: "#app",
data: {
name: "你好世界 我不好",
school: {
name: "拉钩教育",
mobile: "1001001",
},
names: ["尼古拉斯", "赵四", "凯撒"],
},
});
</script>
</html>
声明式渲染的好处:
Vue中的声明式渲染,简单理解就是我们声明数据,Vue帮我们将数据渲染到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">
<h2>{{name}}</h2>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
name: "Hello Word! !",
},
});
</script>
</html>
Vue常用指令:
根据官网的介绍,指令 是带有 v- 前缀的特殊属性,通过指令来操作DOM元素
v-text 指令:
作用:获取data数据,设置标签的内容
注意:默认写法会替换全部内容,使用插值表达式{{}}可以替换指定内容
<!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>{{message}}高薪训练营</h2>
<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>
上面是设置innerText的值,下面是设置innerHTML的值
v-html 指令:
作用: 设置元素的 innerHTML (可以向元素中写入新的标签)
<!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>
</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>
</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-on 指令:
作用: 为元素绑定事件,比如: v-on:click,可以简写为 @click=“方法”
绑定的方法定义在 VUE实例的,method属性中
<!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>
</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: {
show: function () {
alert("程序员在加班!!");
},
changeFood: function () {
console.log(this.food);
this.food += "真好吃";
},
},
});
console.log(VM)
</script>
</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>
<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>
<script>
</script>
</html>
v-show指令:
作用: v-show指令,根据真假值,切换元素的显示状态
<!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>
</style>
</head>
<body>
<div id="app">
<input type="button" value="切换状态" @click="changeShow" />
<img v-show="isShow" src="./img/car.gif" />
<img v-show="age > 18" src="./img/car.gif" />
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
isShow: true,
age: 19,
},
methods: {
changeShow: function () {
this.isShow = !this.isShow;
},
},
});
</script>
</html>
v-if 指令:
作用: 根据表达值的真假,切换元素的显示和隐藏( 操纵dom 元素 )
<!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>
</style>
</head>
<body>
<div id="app">
<input type="button" value="切换状态" @click="changeShow" />
<img v-if="isShow" src="img/car.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-bind 指令:
作用: 设置元素的属性 (比如:src,title,class)
<!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>
</style>
</head>
<body>
<div id="app">
<img src="img/lagou.jpg" alt="" />
<img v-bind:src="imgSrc" />
<img v-bind:src="imgSrc" :title="imgTitle" />
<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/lagou.jpg",
imgTitle: "拉钩教育",
size: 50,
},
});
</script>
</html>
v-for 指令:
作用: 根据数据生成列表结构
<!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>
</style>
</head>
<body>
<div id="app">
<input type="button" value="添加数据" @click="add" />
<input type="button" value="移除数据" @click="remove" />
<ul>
<li v-for="(item,index) in arr">
{{index+1}}城市: {{item}}
</li>
</ul>
<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 () {
this.persons.push({ name: "小斌" });
},
remove: function () {
this.persons.shift();
},
},
});
</script>
</html>
v-on 指令补充:
传递自定义参数:函数调用传参
事件修饰符:对事件触发的方式进行限制
<!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>
</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>
MVVM模式:
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式
MVVM模式将页面,分层了 M 、V、和VM,解释为:
Model:负责数据存储
View:负责页面展示
View Model:负责业务逻辑处理(比如Ajax请求等),对数据进行加工后交给视图展示
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fc06ed24637cb720cfda5462e1d065e4.png#pic_center)
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键
从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据
从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素
MVVM的思想,主要是为了让我们的开发更加的方便,因为MVVM提供了数据的双向绑定
v-mode 指令:
作用:获取和设置表单元素的值(实现双向数据绑定)
双向数据绑定:
单向绑定:就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新
双向绑定:用户更新了View,Model的数据也自动被更新了
这种情况就是双向绑定(得值,改值,设置值,上面说过的get和set类似的操作,双方都有)
什么情况下用户可以更新View呢:
填写表单就是一个最直接的例子
当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态
那就相当于我们把Model和View做了双向绑定:
<!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>
</style>
</head>
<body>
<div id="app">
<input type="button" value="修改message" @click="update" />
<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>
var VM = new Vue({
el: "#app",
data: {
message: "拉钩教育训练营",
password: 123,
},
methods: {
update: function () {
this.message = "拉钩";
},
},
});
</script>
</html>
v-model指令总结:
v-model 指令的作用是便捷的设置和获取表单元素的值
绑定的数据会和表单元素值相关联
双向数据绑定
实现简单记事本 :
<html>
<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>
<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>
<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>
<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>
</body>
<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 () {
this.list.push(this.inputValue);
},
remove: function (index) {
console.log(index);
this.list.splice(index, 1);
},
clear: function () {
this.list = [];
},
},
});
</script>
</html>
html,
body {
margin: 0;
padding: 0;
}
body {
background: #fff ;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f1b7b7;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
#app {
background: #fff;
margin: 180px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#app input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#app input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#app input::input-placeholder {
font-style: italic;
font-weight: 300;
color: gray;
}
#app h1 {
position: absolute;
top: -160px;
width: 100%;
font-size: 60px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, .8);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 16px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
width: 1px;
height: 1px;
border: none;
opacity: 0;
position: absolute;
right: 100%;
bottom: 100%;
}
.toggle-all + label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all + label:before {
content: "❯";
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked + label:before {
color: #737373;
}
.listview {
margin: 0;
padding: 0;
list-style: none;
max-height: 420px;
overflow: auto;
}
.listview li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
height: 60px;
box-sizing: border-box;
}
.listview li:last-child {
border-bottom: none;
}
.listview .view .index {
position: absolute;
color: gray;
left: 10px;
top: 20px;
font-size: 16px;
}
.listview li .toggle {
text-align: center;
width: 40px;
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none;
-webkit-appearance: none;
appearance: none;
}
.listview li .toggle {
opacity: 0;
}
.listview li .toggle + label {
background-image:
url("data:image/svg+xml;utf8,
%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22
%20height%3D%2240%22%20viewBox%3D%22-10%20-
18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%
3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20
stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center left;
}
.listview li .toggle:checked + label {
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/
svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-
18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%
3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%
20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%
235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E");
}
.listview li label {
word-break: break-all;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.listview li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.listview li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
.listview li .destroy:hover {
color: #af5b5e;
}
.listview li .destroy:after {
content: "×";
}
.listview li:hover .destroy {
display: block;
}
.listview li .edit {
display: none;
}
.listview li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: "";
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 50px auto 0;
color: #bfbfbf;
font-size: 15px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
@media screen and (-webkit-min-device-pixel-ratio: 0) {
.toggle-all,
.listview li .toggle {
background: none;
}
.listview li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
.inputNum {
vertical-align: middle;
height: 22px;
border: 1px solid #d0d0d0;
text-align: center;
}
.btn {
display: inline-block;
vertical-align: middle;
background: #f0f0f0 no-repeat center;
border: 1px solid #d0d0d0;
width: 50px;
height: 50px;
border-radius: 2px;
box-shadow: 0 1px rgba(100, 100, 100, 0.1);
color: #666;
transition: color 0.2s, background-color 0.2s;
}
.btn:active {
box-shadow: inset 0 1px rgba(100, 100, 100, 0.1);
}
.btn:hover {
background-color: #e9e9e9;
color: #333;
}
.btn_plus {
background-image: linear-gradient(to top, currentColor, currentColor),
linear-gradient(to top, currentColor, currentColor);
background-size: 20px 2px, 2px 20px;
}
.btn_minus {
background-image: linear-gradient(to top, currentColor, currentColor);
background-size: 20px 2px, 2px 20px;
}
实际上并非要完全按照上面的说明双向绑定,其实你可以认为vue是利用的js的某些功能在原来的从js中获取的信息是否改变原来给他的信息,就如b =c ,d=b,其中d是浏览器的显示,c是数据的渲染,但是d=b的这个b并不是指向c的,所以d和b都是一个数,其中d和b给的数或者说备份的变量是双向的,那么双向绑定就是说明b和d是否绑定的意思,具体如何实现,二进制肯定帮我们完成了,我们了解即可
在设置同步和异步时,false不能加上分号(引号),因为加上分号(引号)认为是true
所以直接写false,但是ajax本来就是用来异步的,所以false现在虽然可以用,但被弃用了,所以可能以后会没有这个操作方式了
axios介绍:
VUE中结合网络数据进行应用的开发
目前十分流行网络请求库,专门用来发送请求,其内部还是ajax,进行封装之后使用更加方便
axios作用:在浏览器中可以帮助我们完成 ajax异步请求的发送
Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax
axios入门:
使用步骤:
导包:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
请求方式,以GET和POST举例
GET:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b1e8e5d81b148470775a67a6471ef763.png#pic_center)
POST:
<!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>
</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>
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);
}
);
};
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>
通过vue+axios 完成一个获取笑话的案例:
<!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>
</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>
var VM = new Vue({
el: "#app",
data: {
joke: "笑口常开",
},
methods: {
getJoke: function () {
var that = this;
axios.get("https://autumnfish.cn/api/joke").then(
function (resp) {
console.log(resp.data);
console.log(that.joke);
that.joke = resp.data;
},
function (error) {}
);
},
},
});
</script>
</html>
现在说明Vue的作用:可以将数据进行对元素的基本随意改动,方法的基本随意调用,语法简洁,数据集中,数据绑定,重在单体
天气查询案例 :
<!DOCTYPE html>
<html lang="en">
<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>
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/index.css" />
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<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>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./js/main.js"></script>
</body>
</html>
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);
that.weatherList = resp.data.data.forecast;
},
function (error) {}
);
},
},
});
解决页面闪烁问题 :
我们发现访问天气预报案例页面时,使用插值表达式的地方出现了闪烁问题
是因为vue.js太多加载缓慢,使得原来的语法如{{}}还没有进行找到,即识别替换,造成刷新时{{}}会出现一下
我们可以使用下面的指令来防止这种情况(其实也可以将vue.js放在前面)
v-cloak指令:
作用: 解决插值表达式闪烁问题
当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码
我们可以使用 v-cloak 指令来解决这一问题
<style>
[v-cloak] {
display: none;
}
</style>
<div class="wrap" id="app" v-cloak>
computed 计算属性:
什么是计算属性:
在Vue应用中,在模板中双向绑定一些数据或者表达式,但是表达式如果过长,或者逻辑更为复杂时
就会变得臃肿甚至难以维护和阅读,比如下面的代码:
<div>
</div>.
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>
</style>
</head>
<body>
<div id="app">
<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总结:
定义函数也可以实现与计算属性相同的效果,都可以简化运算
不同的是计算属性是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值
filter 过滤器:
什么是过滤器:
过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原来的数据
只是在原数据的基础上产生新的数据
数据加工车间,对值进行筛选加工
过滤器使用位置:
双括号插值内:
v-bind绑定的值的地方:
过滤器:
局部过滤器:
<!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>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
price: 200,
},
methods: {
},
computed: {
},
filters: {
addIcon(value) {
return "$" + value;
},
},
});
</script>
</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>
<style>
</style>
</head>
<body>
<div id="app">
<p>{{user.name | changeName}}</p>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
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>
总结:
过滤器常用来处理文本格式化的操作
过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
过滤器应该被添加在 JavaScript 表达式的头部(如全局),局部一般是尾部,由"管道"符号指示
全局是给所有el所对应的,而局部只有一个el所对应的
watch 侦听器:
什么是侦听器 :
Vue.js 提供了一个方法 watch,它用于观察Vue实例上的数据变动
作用:当你有一些数据需要随着其它数据变动而变动时,可以使用侦听属性
案例演示:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f4ac1185d0d5568dd3a3cf7b6e026bab.png#pic_center)
先看计数器:
<!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>计数器:{{count}}</h2>
<input type="button" @click="count++" value="点我+1" />
</div>
</body>
<script src="./js/vue.min.js"></script>
<script>
var VM = new Vue({
el: "#app",
data: {
count: 1,
},
watch: {
count: function (nval, oval) {
alert("计数器发生变化: " + oval + " 变化为 " + nval);
},
},
});
</script>
</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">
<label>名:<input type="text" v-model="fristName" /></label>
<label>姓:<input type="text" v-model="lastName" /></label>
{{fullNameComputed}}
</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) {
this.fullName = nval + " " + this.lastName;
},
lastName: function (nval, oval) {
this.fullName = this.fristName + " " + nval;
},
},
});
</script>
</html>
Component 组件 :
组件介绍:
组件(Component)是自定义封装的功能
在前端开发过程中,经常出现多个网页的功能是重复的
而且很多不同的页面之间,也存在同样的功能
我们将相同的功能进行抽取,封装为组件,这样,前端人员就可以在组件化开发时,只需要书写一次代码,随处引入即可使用
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cd475565b1074f6bbf17214136751716.png#pic_center)
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">
<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>",
data() {
return {
msg: "这lagou-header是组件中的数据部分",
};
},
methods: {
hello() {
alert("你好");
},
},
});
var VM = new Vue({
el: "#app",
data: {},
methods: {},
});
</script>
</html>
Ot对象内部是其他的对象,即this._init()方法,有特别的知识使得方法里自带一些参数
就如Window一样,如window.创建的对象.a=9,那么你创建的对象里面,就有a这个属性(key)了
这就是Vue有属性(key)的原因
局部组件:
相比起全局组件,局部组件只能在同一个实例内才能被调用
局部组件的写法和全局组件差不多
唯一不同就是:局部组件要写在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">
<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>
注意:
创建局部组件,注意 components,注意末尾有 “s”,而全局组件是不用+ “s” 的
这意味着,components 里可以创建多个组件,从结构上可以看出,是用键值对形式的(即可以加多个)
组件与模板分离 :
由于把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>
<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的添加和替换,只注重内容(一般全局来识别,因为他在任何时候都识别,而不像局部一样,只识别一次)
总结:
上面这种写法,浏览器会把 html 里的 template 标签过滤掉
所以 template 标签的内容是不会在页面中展示的,直到它被 JS 中的 Vue 调用。
在 html 中,template 标签一定要有一个 id,因为通过 id 是最直接被选中的
data 和 methods 等 参数,全部都要放到 Vue 实例里面写
注意: </6>代表 <!–/6>,在浏览器中,一般数字会这样,而<1>就代表<1>显示在浏览器中,一般数字会这样,这应该是浏览器的原因
Vue生命周期:
生命周期图示:
每个Vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期
了解生命周期的好处:
找错误
解决需求
下图展示了实例的生命周期,你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d8d65dcb6ac8e2e63a99c25e0c677f05.png#pic_center)
钩子函数介绍:
生命周期中的钩子函数
钩子函数:钩子函数是在一个事件触发的时候,在系统级捕获到了他,然后做一些操作
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ed8b6669905043d4accda4333aa816a8.png#pic_center)
可以这样的认为:
beforeCreate():创建Vue实例,参数中这个最先被设置,即先调用这个方法,其他参数还没设置
created():其他参数被设置了,浏览器的所以内容被隐藏,这时调用这个方法后,之后显示出来
beforeMount():找到了对应的Vue的属性,但是就只是找到了而已,并没有进行操作,即设置页面内容
这时调用这个方法,可以说是还没直接使用这个key值来设置页面内容
mounted():我们已经操作完了,设置了内容,即调用这个方法,就如js设置完innerHTML或者innerText后的操作方法
beforeUpdate():当data的值进行更新时,即被修改了
但是还没有进行相关的set设置,即网页上还没有改变,那么就执行这个方法
updated():data的值更新,且set设置了页面内容,即调用了这个方法,就如js设置完innerHTML或者innerText后的操作方法
<!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 = "气吞万里如虎!";
},
},
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)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/28f0fadd7e4ec4e0fe0c539ed8b6356b.png#pic_center)
什么是SPA:
单页面Web应用(single page web application,SPA),就是只有一张Web页面的应用
是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序
单页应用不存在页面跳转,它本身只有一个HTML页面
我们传统意义上的页面跳转在单页应用的概念下转变为了 body 内某些元素的替换和更新,举个例子:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5444c96cde1c1fd31b19359c86d9a853.png#pic_center)
整个body的内容从登录组件变成了欢迎页组件, 从视觉上感受页面已经进行了跳转
但实际上,页面只是随着用户操作,实现了局部内容更新,依然还是在index.html 页面中
单页面应用的好处:
用户操作体验好,用户不用刷新页面,整个交互过程都是通过Ajax来操作
适合前后端分离开发,服务端提供http接口,前端请求http接口获取数据,使用JS进行客户端渲染
缺点:功能全部放在一个页面中,不好维护,简单来说组件是单页面的基础操作,替换组件就是单页面的核心功能
路由相关的概念:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a52c59d3022551df6ac77b3aaa8fd1f6.png#pic_center)
这些路由并不是真正的路由,只是一个作用而已,所以可以称为Vue的路由
实际上这样的单页面的其他页面就是组件的变化
方法里参数少些的那些值,一般是undefined
使用路由:
<!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>
</style>
</head>
<body>
<div id="app">
<h1>渣浪.com</h1>
<p>
<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>
<script src="./js/vue.min.js"></script>
<script src="./js/vue-router.min.js"></script>
<script>
const home = { template: "<div>首页</div>" };
const news = { template: "<div>新闻</div>" };
const routes = [
{ path: "/home", component: home },
{ path: "/news", component: news },
];
const router = new VueRouter({
routes: routes,
});
var VM = new Vue({
router,
}).$mount("#app");
</script>
</html>
路由总结:
路由可以指定的出现组件(页面)
router是Vue中的路由管理器对象,用来管理路由
route是路由对象,一个路由就对应了一条访问路径,一组路由用routes表示
每个路由对象都有两部分 path(路径)和component (组件)
router-link 是对a标签的封装,通过to属性指定连接
router-view 路由访问到指定组件后,进行页面展示
这时当你运行时,会在倒数第二个路径位置加上一个#,代表这个有路由操作,操作时无论怎么刷新,都不会变
即他们操作的值,已经固定的,即操作后,就永久的在那里了,实际上是路径的变化,因为刷新的是路径
当你点击一个地址时,会在原来的#/后面加上对应地址,所以刷新的就是这个地址,所以不会变
即也可以手动的添加路径来操作(访问)
这样的一些操作,使得多个页面,真正的变成了单页面了
最后注意:Vue的渲染,都是js造成的,虽然也可以认为是浏览器的处理(他来操作js的)
这里我们可以测试一下:
将template标签的js进行导出,由上面的路由接收,看看可不可以使用,可以发现在html中script一般是操作不了导入导出的,因为他是在node.js环境上处理的,具体来说是他里面的CommonJS 模块语法(具体来说,组件之间只有全局可以嵌套,且路由不能加组件(说的不是单纯的代码,是组件这个整体,不是上面的路由的例子),这是建立在单纯的script中的,也就是没有在node.js中操作,在下一章博客会说明的)
当然,可以考虑组件的嵌套,虽然基本只能是全局,具体可以考虑下一章的具体说明,这里就不给出了