朝小闇的博客

海上月是天上月,眼前人是心上人

Vue(1.基础入门)

1.简介

1.1 概念介绍

  • Vue 是一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular(模块化)和React(虚拟DOM)的优点,与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如: vue-router,vue-resource,vuex)或既有项目整合。

1.2 MVVM

  • Model:模型层,在这里表示JavaScript对象;
  • View:视图层,在这里表示DOM(HTML 操作的元素);
  • ViewModel:连接视图和数据的中间件,Vue.js 就是MVVM中的ViewModel层的实现者

image-20200830141507977

  • View层展现的不是Model层的数据,而是ViewModel的数据,由ViewNodel负责与 Model层交互,这就完全解耦了View层和Model层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。

1.3 搭配环境

  • 下载vue.js文件:

  • 如果不下载到本地,可以使用cdn外部引入:

    • <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24

      - 再在IDEA中 `settings->plugins`中搜索安装vue.js:
      ![image-20200830144613941](https://cdn.jsdelivr.net/gh/ZHAOXIAOAN/CDNBlog/Img/031.png)

      - 安装之后重启再设置下一步:

      ![在这里插入图片描述](https://cdn.jsdelivr.net/gh/ZHAOXIAOAN/CDNBlog/Img/032.png)

      附模板:

      ```vue
      <template>

      </template>

      <script>
      export default {
      name:"${NAME}"
      }
      </script>

      <style scoped>

      </style>

注:上图与模板代码取自博客:https://blog.csdn.net/jdq8576/article/details/104055707/

  • 然后就可以在IDEA文件中new一个Vue Component文件啦!

image-20200830145017226


2.基础语法

2.1 初步使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--view层,模板-->
<div id="app">
<!--展示格式-->
{{message}}
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app", //el属性用于绑定id号,且双向绑定,vm绑定id的同时,id也绑定了vm,使id视图层能随时取到vm的值
data: { //data属性为数据存储区
message:"hello,vue!"
}
});

//页面内容能够随message数值改变而随时改变,不需要刷新页面
vm.message = 'hello zhaoxiaoan'
>"hello zhaoxiaoan"
</script>
  • Vue常用的七个属性:
    • el :占位符,用来绑定标签、id和class,指示编译器解析;
    • data :存放数据区域;
    • methods :存放方法逻辑区域;
    • render :创建Virtual Dom
    • computed :用于计算
    • watch
      • watch:function(new,old){};
      • 监听data中数据的变化;
    • template :用来设置模板,替换页面元素,包括占位符;

2.2 v-bind指令

  • 该指令的含义是绑定信息,如 v-bind:title="massage" 就是绑定了标题信息,将鼠标移动到<span>标签语句悬停可显示其绑定信息;
  • v-bind:可以简写为 : ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--使用v-bind指令可以自动引入v-bind使用链接-->
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">

<!--view层,模板-->
<!-- v- 都是vue指令 -->
<div id="app">
<span v-bind:title="massage">
鼠标悬停几秒查看此处绑定的信息
</span>
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
massage:"hello,vue"
}
});

</script>

2.3 if判断语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--view层,模板-->
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
type:"A"
}
});

</script>

2. 4 循环列表(重要)

  • 列表配合for循环就可以简单实现从数据库中导出数据并且循环输出成列表展示;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--view层,模板-->
<div id="app">
<!--v-for="(item,index) in items" 格式类似于forEach,定义item取items数组中每个元素,index取索引下标,不用可不取-->
<li v-for="item in items">
<!--item.message用于展示-->
{{item.message}}
</li>
</div>

<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
//数组元素用来给列表li循环遍历
items: [
{message:"hello,vue"},
{message:"hello zhaoxiaoan"}
]
}
});

</script>

image-20200830153345031

2.5 v-on 绑定事件

  • v-on: 用来绑定事件,如事件click ,其余事件可以查找jQuery事件文档(可以自己创建新事件);
  • v-on:可以简写为 @
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">

<!--view层,模板-->
<div id="app">
<button v-on:click = "sayHi">Click Me</button>
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "hello,vue!"
},
//方法只能存放在methods中
methods: {
sayHi:function (envent) {
alert(this.message);
}
}
});

</script>

image-20200830155311872


3.双向绑定(重点)

  • 使用v-model指令;
  • v-model指令会忽略所有表单元素的checked、selected等值,因此在下拉框中初始默认选择为空,必须设置一个disabled不可选中项并且设置其值为空来作为默认选择域;

3.1 文本

  • 本质是{{message}}用来绑定data{message}显示内容,而message又通过v-model="message"绑定了<input>文本域,所以当<input>输入框值域变化时修改了data{message}数据,接着message就跟着变化;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--view层,模板-->
<div id="app">
输入的文本:<input type="text" v-model="message">
{{message}}
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "hello,vue!"
},
});

</script>

image-20200830164055648

3.2 textarea文本域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--view层,模板-->
<div id="app">
输入的文本:
<textarea v-model="message"></textarea>>
{{message}}
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "hello,vue!"
},
});

</script>

image-20200830164801393

3.3 radio单选框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--view层,模板-->
<div id="app">
性别:
<input type="radio" name="sex" value="男" v-model="message">
<input type="radio" name="sex" value="女" v-model="message">
<p></p>
{{message}}
</div>

<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: ""
},
});

</script>

image-20200830165053896

3.4 select下拉框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--view层,模板-->
<div id="app">
下拉框:
<select v-model="message">
<option value="" disabled >--请选择--</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>选择了:{{message}}</p>
</div>

<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: ""
},
});

</script>

image-20200830165542144

image-20200830165627407


4.组件

  • 组件最大的作用就是其良好的复用性,但是复用性的本质只能复用框架外围,内在的本质数据必须从另一方获取,接下来讲述的就是获取数据的过程;

4.1 新建component组件

  • 给新组件命名为zhaoxiaoan
  • template为替换的模板内容;
1
2
3
4
5
6
7
8
9
10
11
Vue.component("zhaoxiaoan",{
template: '<li>Hello</li>'
})

//做好准备工作,绑定好id,存好数据
let vm = new Vue({
el: "#app",
data: {
items: ["Java","Linux","前端"]
},
});

4.2 使用新组件

  • 从绑好的Data中遍历取出数据;
  • 并且使用v-bind:itemX绑定新变量itemX,并且将v-for遍历得到的数据赋值给新变量
1
2
3
<div id="app">
<zhaoxiaoan v-for="item in items" v-bind:itemX="item"></zhaoxiaoan>
</div>

4.3 将数据传入新组件

  • 使用属性props接收新参数itemX此参数就是v-bind新定义并且绑定的那个变量,最终这个新变量传递给template模板中的itemX
1
2
3
4
Vue.component("zhaoxiaoan",{
props:['itemX'],
template: '<li>{{itemX}}</li>'
})

最终代码与运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--view层,模板-->
<div id="app">
<zhaoxiaoan v-for="item in items" v-bind:item="item"></zhaoxiaoan>
</div>


<!--导入vue.js包-->
<script src="../lib/vue.js"></script>
<script>
Vue.component("zhaoxiaoan",{
props:['item'],
template: '<li>{{item}}</li>'
})

let vm = new Vue({
el: "#app",
data: {
items: ["Java","Linux","前端"]
},
});

</script>

image-20200830171934341


5.Axios异步网络通信(重点)

5.1 Axios简介

  • Axios是一个开源的可以用在浏览器端和 Node3S 的异步通信框架,它的主要作用就是实现 AJAX异步通信,其功能特点如下:

    • 从浏览器中创建 XMLHttpRequests
    • 从 node.js 创建http请求
    • 支持 Promise API [JS中链式编程]
    • 拦截请求和响应
    • 转换请求数据和响应数据
    • 取消请求
    • 自动转换 JSON 数据
    • 客户端支持防御 XSRF(跨站请求伪造)
  • 由于Vue.js是一个视图层框架并且作者(尤雨溪)严格准守SoC(关注度分离原则),所以Vue.js并不包含AJAX的通信功能,为了解决通信问题,作者单独开发了一个名为vue-resource的插件,不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios框架。少用jQuery,因为它操作Dom太频繁

5.2 Vue实例生命周期图示介绍

  • 这是一个Vue实例生命周期,在生命周期过程中会执行相应的“钩子函数”,这些“钩子函数”是可以被外部调用进而影响到整个实例的;

lifecycle

5.3 引入Axios

  • 外部cdn引入:
1
<script src="https://unpkg.com/axios/dist/axios.min.js "></script>
  • 官方文档安装Axios:

http://www.axios-js.com/zh-cn/docs/vue-axios.html

5.4 模拟网络通信

  • 开发的接口大部分使用JSON格式,先在项目里模拟一段JSON数据:
    • 创建一个新文件命名为data.json ,数据如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"name":"狂神说Java" ,
"url":"https://blog.kuangstudy.com",
"page": 1,
"isNonProfit": true,
"address": {
"street":"含光门",
"city":"陕西西安",
"country" :"中国"
},
"links" :[
{
"name": "bilibili",
"url": "https://space.bilibili.com/95256449"
},
{
"name": "狂伸说java",
"url": "https://blog.kuangstudy.com"
},
{
"name":"百度",
"url": "https://www.baidu.com/"
}
]
}
  • html文件代码如下:

    1. 先写mounted()函数,在这个钩子函数中调用axios.get()获取json文件数据;

    2. response=>(this.info=response.data)
      //这条语句是ES6新特性,=>后面相当于函数内容,即请求响应后执行函数语句将请求响应的数据赋值给info
      
      1
      2
      3

      3. ```javascript
      //data()函数return是将其中定义的键值对属性值在mounted调用之后返回给data,实现data属性的动态传递
    3. 再通过双向绑定在html中引用data属性的数值;

    4. 对于链接标签中链接的动态生成,则使用v-bind指令将href属性的值绑定为info.url,不能直接将info.url传递给href,否则只能识别为一串字符串;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<div id="vue">
<div>{{info.name}}</div>
<div>{{info.address.street}}</div>

<a v-bind:href="info.url">click</a>
</div>

<!--引入js文件-->
<script src="../lib/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el: "#vue" ,
data(){
return{
info: { //json文件中的属性只有在此处同名定义之后,接收数据后才能被调用
name: null,
address: {
street: null,
city: null,
country: null
},
url:null
}
}
},
mounted(){ //钩子函数,链式编程
axios.get("../data.json").then(response=>(this.info=response.data));
}
});
</script>

</body>
</html>

image-20200902223854253

  • json文件在编码时没有使用UTF-8编译,所以上述请求执行后会得到乱码内容,解决方法是将json文件用notepad++打开之后在视窗栏 编码->使用UTF-8编码和转为UTF-8编码;

6.计算属性

  • 存在于computed属性中;

  • methods与computed属性中的函数名不能重名,否则优先调用methods中的函数而不会调用computed中的属性(定义为函数,调用为属性);

  • 调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;

  • computed属性中的缓存只在数据发生增删改之后才会重新刷新变化,而methods内的函数随时变化;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
<p>currentTime1 {{currentTime1()}}</p><!--注意,调用methods内的函数使用函数调用-->
<p>currentTime2 {{currentTime2}}</p><!--注意,调用computed内的函数使用属性调用-->
</div>

<!--引入js文件-->
<script src="../lib/vue.js"></script>
<script>
var vm = new Vue({
el: "#app" ,
data: {
message: "hello,world"
},
methods:{
currentTime1:function () {
return Date.now();//返回一个时间戳
}
},
computed:{
currentTime2:function () {
this.message;
return Date.now();//返回一个时间戳
}
}

});
</script>

image-20200903102347608


7.插槽slot

  • 插槽的本质就是嵌套组合复用;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<div id="app">
<todo>
<!--v-bind: 简略形式为 : -->
<!--v-on: 简略形式为 @ -->

<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-item" v-for="item in todoItems" :item="item"></todo-items>
</todo>
</div>

<!--引入js文件-->
<script src="../lib/vue.js"></script>
<script>
Vue.component("todo",{
/*template: '<div>' +
'<slot></slot>' +
'<ul>' +
'<slot></slot>' +
'</ul>' +
'</div>'*/
//使用一个 \ 就可以直接换行
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-item"></slot>\
</ul>\
</div>'
//slot插槽通过name属性确定每一个slot插槽独一无二,在<div>中可通过此属性连接其它组件
});

Vue.component("todo-title",{
props:["title"],
template: '<div>{{title}}</div>'
});
Vue.component("todo-items",{
props:["item"],
template: '<li>{{item}}</li>'
});




var vm = new Vue({
el: "#app" ,
data:{
title: "学习篇",
todoItems:["Java","Linux","前端"]
}

});
</script>

image-20200903110407351


8.自定义事件分发

  • 实现在slot基础上的自定义删除事件;
  • 具体问题及解决方式:
    • component组件中定义事件函数,但是并不能直接修改vue实例内容
      • 间接,在vue实例中定义函数事件用于删除data数据内容;
      • 将该事件removeItem 通过 v-on 绑定到自定义事件 remove 上;
      • 再在component组件中通过this.$emit('remove',index)自定义事件分发传参并调用自定义事件remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<div id="app">
<todo>
<!--v-bind: 简略形式为 : -->
<!--v-on: 简略形式为 @ -->

<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-item" v-for="(item,index) in todoItems"
:item="item" :index="index" @remove="removeItem(index)" ></todo-items>
</todo>
</div>

<!--引入js文件-->
<script src="../lib/vue.js"></script>
<script>
Vue.component("todo",{
//使用一个 \ 就可以直接换行
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-item"></slot>\
</ul>\
</div>'
//slot插槽通过name属性确定每一个slot插槽独一无二,在<div>中可通过此属性连接其它组件
});

Vue.component("todo-title",{
props:["title"],
template: '<div>{{title}}</div>'
});
Vue.component("todo-items",{
props:["item","index"],//传入两个参数
template: '<li>--{{index}}--{{item}} <button @click="remove(index)">删除</button></li>',
methods:{
remove: function (index) {
this.$emit('remove',index);//自定义事件固定调用格式
}
}
});

var vm = new Vue({
el: "#app" ,
data:{
title: "学习篇",
todoItems:["Java","Linux","前端"]
},
methods:{
removeItem:function (index) {
this.todoItems.splice(index,1);//从index索引删除一个数组元素
}
}

});
</script>
  • 点击删除按钮能够动态删除data数据并且刷新页面显示:

image-20200903121218463

关系示意图:最终都是通过前端的view视图来连接

QQ图片20200903120909

-------- 本文结束 感谢阅读 --------