My_Study_Vuejs’s 学习笔记

github地址

邂逅vue

遇见vue

为什么学习vuejs

vue学习的原因很多,可能有如下的集中原因:

  • 公司将原来的项目进行vue重构

  • 公司使用vue技术栈

  • 大量前段工作岗位对vue有一定要求

  • vue非常火,国人开发维护。

简单认识vue

Vue (读音 /vjuː/)

vue的特点

  • vue是渐进式框架的

  • 解耦视图和数据

  • 前段路由技术

  • 状态管理

  • 虚拟dom

安装Vue

安装方式比较多

cdn引入

cdn方式推荐代码部署在服务器上面的比较好, 让用户可以使用cdn技术快速访问到文件。

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.vue"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

下载引入

下载文件放到工程目录,然后进行引入方式。

<script src="../js/vue.vue"></script>

npm安装

npm命令安装vue。

npm install vue

cli和npm结合

后续通过webpack和CLI的使用,我们使用该方式。

体验vue

hello vue

通过简单的hello vue 展示一个定义的数据。

 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
<!DOCTYPE html>
<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>

    </div>

    <script src="../js/vue.js"></script>
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                "message": "123"
            }
        })
    </script>
</body>

</html>

可以在浏览器进行数据修改,然后自动页面修改。

_images/mvvm.png

vue显示列表

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>

<div id="app">
    <ul>
        <li v-for="zoom in zooms ">
            {{ zoom }}
        </li>
    </ul>

</div>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            zooms: ["dog","cat","panda"]
        }
    })
</script>

</body>
</html>

vue简单计数器

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>

<div id="app">
    <h2>{{ cnt }}</h2>
    <button @click="add">+</button>
    <button @click="sub">-</button>

</div>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            cnt:1,
        },
        methods:{
            add: function (){
                this.cnt+=1
            },
            sub: function(){
                this.cnt-=1
            }
        }

    })
</script>

</body>
</html>

mvvm架构

mvvm 是model view view model 的合称。

data和vue对象的分离

vue中的mvvm

_images/mvvm.png
View层:

视图层 在我们前端开发中,通常就是DOM层。 主要的作用是给用户展示各种信息。

Model层:

数据层 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。

VueModel层:

视图模型层 视图模型层是View和Model沟通的桥梁。 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data

vue的options

vue的options有很多

主要的有以下几个

  • el: 决定vue实例管理哪个dom。

  • data: vue实例对应的数据对象。

  • methods: 定义方法,方便其他地方调用。

mvvm生命周期

_images/vue生命周期.png

基础语法

插值操作

通过插值操作可以完成vue对象的数据,填充到html中去。

<h2> {{ message }} </h2>

v-once

可以完成vue仅仅一次的数据绑定,后续的数据修改不在同步页面。

v-html

可以将数据中的html内容,以html展示到页面上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <p>Using mustaches: {{ rawHtml }}</p>
    <p>Using v-html directive: <span v-html="rawHtml"></span></p>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            rawHtml: '<span style="color:red"> this should be red</span>'
        }
    })
</script>
</body>
</html>

v-text

可以将数据中的html内容,以text展示到页面上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <p>Using mustaches: {{ rawHtml }}</p>
    <p>Using v-text directive: <span v-text="rawHtml"></span></p>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            rawHtml: '<span style="color:red"> this should be red</span>'
        }
    })
</script>
</body>
</html>

v-pre

用于跳过这个元素和他子元素的编译过程,用于展示原本内容。

v-cloak

某些情况下 ,浏览器可能会直接展示未编译的mustache标签。 通过此可以不展示这些信息。

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>Document</title>
    <style>
        [v-cloak] {
            display: none   ;
        }
    </style>
</head>
<body>

<div id="app" v-cloak>
    <h2  >{{ cnt }}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    setTimeout(function(){
    let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        }
    })},3000)
</script>
</body>
</html>

绑定属性

v-bind可以绑定属性。

绑定基本使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <img :src="srcUrl" alt="">

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            srcUrl: "https://i1.hdslb.com/bfs/face/c850c18ae6b507d0ef34837f53a51090b6a7451f.jpg@96w_96h_1c.webp"
        }
    })
</script>
</body>
</html>

动态绑定class

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active{
            color:  red;
        }
        .line{
            background-color: blue;
        }
    </style>
</head>
<body>
<div id="app">
    <h2 v-bind:class="getClass()">{{message}}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            message: "panda",
            isActive: true,
            isLine: true
        },
        methods:{
            getClass: function(){
                return {active:this.isActive,line:this.isLine}
            }
        }
    })
</script>
</body>
</html>

动态绑定style

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active{
            color:  red;
        }
        .line{
            background-color: blue;
        }
    </style>
</head>
<body>
<div id="app">
    <h2 v-bind:style="{fontSize: messageFontSize}">{{message}}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            message: "panda",
            messageFontSize: "100px",
        },
        methods:{

        }
    })
</script>
</body>
</html>

v-for和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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .active{
            color:  red;
        }
        .line{
            background-color: blue;
        }
    </style>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(zoom,index) in zooms">
            <p v-bind:class="{active: curentIndex==index}" @click="ChangeClass($event,index)"> {{index }} - {{ zoom }} </p>
        </li>
    </ul>
</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            zooms: ['cat','dog','pig'],
            curentIndex:0,
            isActive: false
        },
        methods:{
            ChangeClass: function (event,index){
                this.curentIndex =index
            }
        }
    })
</script>
</body>
</html>

计算属性

可以根据已有的属性生成其他属性。

基本使用

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h2>{{ fullName }}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            firstName: "jie di",
            secondName: "zhao",
        },
        computed:{
            fullName: function (){
                return this.secondName + " " + this.firstName
            }
        }
    })
</script>
</body>
</html>

复杂使用

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h2>{{ totalPrice }}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            books: [
                {id:1,name:'abc',price:100},
                {id:2,name:'abc',price:101},
                {id:3,name:'abc',price:102},
                {id:4,name:'abc',price:103},
            ]
        },
        computed:{
            totalPrice: function (){
                let result=0
                // for (let i=0; i< this.books.length; i++){
                //     result +=this.books[i].price
                // }
                for (let book of this.books){
                    result += book.price
                }
                return result
            }
        }
    })
</script>
</body>
</html>

getter和setter

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <h2>{{ fullName }}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            firstName: "jiedi",
            secondName: "zhao",
        },
        computed:{
            // fullName: function(){
            //     return this.firstName+ this.secondName
            // },

            fullName: {
                get: function (){
                    return this.firstName + " " + this.secondName
                },
                set: function (newValue){
                    const names = newValue.split(" ")
                    this.firstName = names[0]
                    this.secondName =names[1]
                }
            }

        }
    })
</script>
</body>
</html>
_images/getterandsetter.png

计算属性和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
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
            el: "#app",
            data: {
                firstName: "jie di",
                secondName: "zhao",
            },
            methods:{
                getFullName: function(){
                    console.log("------getFullName------")
                    return this.secondName + " " + this.firstName
                },
            },
            computed: {
                fullName: function () {
                    console.log("------fullName------")
                    return this.secondName + " " + this.firstName
                }
            }
        })
        </script>
</body>
</html>
_images/计算属性和方法的对比.png

事件监听

事件监听用于在用户点击、拖拽等场景。

监听基本使用

 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
<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="../js/vue.js"></script>

<div id="app">
    <h2>{{ cnt }}</h2>
    <button @click="add">+</button>
    <button @click="sub">-</button>

</div>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            cnt:1,
        },
        methods:{
            add: function (){
                this.cnt+=1
                console.log("-----add-------" )
            },
            sub: function(){
                this.cnt-=1
                console.log("-----sub-------" )
            }
        }

    })
</script>

</body>
</html>

参数传递

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <button @click="bntClick">按钮1</button>
    <button @click="bntClick2(12,$event)">按钮2</button>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        },
        methods:{
            bntClick(event){
                console.log(event)
            },
            bntClick2(abc,event){
                console.log("第一个参数:" + abc)
                console.log("第二个参数:" + event)
            },
        }
    })
</script>
</body>
</html>
_images/事件参数.png

修饰符

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <div @click="divClick">
        <button @click.stop="btnClick">button1</button>
    </div>
<!--    <div @click="divClick">-->
<!--        <button @click="btnClick">button1</button>-->
<!--    </div>-->

    <form action="baidu">
        <input type="submit" value="提交" @click.prevent="submitClick">
    </form>

        <input type="text" value="提交2" @keyup.enter="keyup">

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {

        },
        methods:{
            btnClick(){
                console.log("btn click")
            },
            divClick(){
                console.log("div click")
            },
            submitClick(){
                console.log("div click")
            },
            keyup(){
                console.log("key up")
            }
        }
    })
</script>
</body>
</html>
_images/事件冒泡.png

条件判断

v-if

简单的判定

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
<!--    <h2 v-if="isShow">{{ cnt }}</h2>-->


    <h2 v-if="isShow">
        <div>abc</div>
        <div>abc</div>
        <div>abc</div>
        {{ message }}
    </h2>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            isShow: true,
            message: "abc",
        }
    })
</script>
</body>
</html>

v-else-if

稍微复杂的判定

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h2 v-if="score>90">优秀 </h2>
    <h2 v-else-if="score>80">良好</h2>
    <h2 v-else-if="score>60">及格 </h2>
    <h2 v-else> 不及格</h2>
    <br>
    <br>
    <br>
    <h2 > {{result}} </h2>
</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            score: 80
        },
        computed:{
            result(){
              let message=''
              if (this.score >90){
                  message ="优秀"
              }
              else if (this.score >80){
                  message="良好"
              }
              else if (this.score >60){
                  message="及格"
              }
              else  {
                  message = "不及格"
              }
              return message
            },
        }
    })
</script>
</body>
</html>

用户登录案例

进行一个用户登录切换的案例

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
   <span v-if="currentType == 'username'">用户名</span>
    <span v-if="currentType == 'email'">用户邮箱</span>
    <input type="text"> </input>
    <button @click="btnClick"> 切登录方式</button>
</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
           currentType: "username",
        },
        methods:{
            btnClick(){
                if (this.currentType == "username" ){
                    this.currentType="email"
                }
                else if (this.currentType == "email" ){
                    this.currentType="username"
                }
            }
        }
    })
</script>
</body>
</html>

v-show

当需要在显示和隐藏之间切回频繁的时候使用 v-show。只有一次切回使用v-if 。

循环

v-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
25
26
27
28
29
30
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(name,index) in names ">{{index }} {{ name}}</li>
    </ul>

    <ul>
        <li v-for="(v,k,index) in person ">{{index }} {{ k}} {{ v}}</li>
    </ul>
</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
           names: [ "panda","pdna02", "panda03"],
            person:{
               name: 'zhaojiedi',
                age: 28,
                weight: 60,
            }
        }
    })
</script>
</body>
</html>

v-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
25
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(v,k,index) in person ">{{index }} {{ k}} {{ v}}</li>
    </ul>
</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            person:{
               name: 'zhaojiedi',
                age: 28,
                weight: 60,
            }
        }
    })
</script>
</body>
</html>

v-for遍历添加key

添加key避免插入对象导致大量的对象移动。

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(name,index) in names " :key="name">{{index }} {{ name}}</li>
    </ul>

    <button @click="btnClick">添加</button>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            names: [ "panda","pdna02", "panda03"],
            person:{
                name: 'zhaojiedi',
                age: 28,
                weight: 60,
            }
        },
        methods:{
            btnClick(){
                this.names.push("panda05")
            },
        }
    })
</script>
</body>
</html>

v-for数组哪些是响应式的

目前一些数组操作是支持响应式的, 不是所有修改都是响应式的。 通过索引方式修改对象是无法响应式的。可以通过splice来实现。 或者使用vue.set方式。

 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
<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="(name,index) in names " :key="name">{{index }} {{ name}}</li>
    </ul>

    <button @click="btnClick">添加</button>

</div>
<script src="../js/vue.js"></script>
<script>
    let app = new Vue({
        el: "#app",
        data: {
            names: [ "panda","pdna02", "panda03"],
            person:{
                name: 'zhaojiedi',
                age: 28,
                weight: 60,
            }
        },
        methods:{
            btnClick(){
                //push
                // pop
                // unshift
                // splice
                // sort
                // reverse

                this.names.push("panda05")

                // 这是非响应式的。
                this.names[0]="zhaojiedi"
                // 这是响应式的
                this.names.splice(1,1,"zhaojiedi")
                //这是是响应式的
                Vue.set(this.names,0,'zhaojiedi')
            },
        }
    })
</script>
</body>
</html>

购入车案例

案例考察点分析

本基础案例考察了如下几点

  • html

  • css

  • v-if,v-else

  • filters

  • methods click

  • computed

  • v-for

详细代码

下面展示各个代码的详细内容。

html
 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>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="style.css">

</head>
<body>


<div id="app">

    <div v-if="infos.length>=1">
<table>
    <th>
        <td>书籍名称</td>
        <td>出版日期</td>
        <td>价格</td>
        <td>购买数量</td>
        <td>操作</td>
    </th>
    <tr v-for="(item,index) in infos" >
        <td>{{index}}</td>
        <td>{{item.name}}</td>
        <td>{{item.date}}</td>
        <td>{{item.price|formatPrice}}</td>
        <td>
            <button @click="sub(item)" :disabled="item.count<=1">-</button>
            {{item.count}}
            <button @click="add(item)">+</button>
        </td>
        <td><button @click="removeLine(index)">移除</button></td>
    </tr>
</table>
   总价: {{totalPrice|formatPrice}}
    </div>
    <h2 v-else>没有商品的</h2>
</div>

<script src="../js/vue.js"></script>
<script src="./main.js"></script>
</body>
</html>
style
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
table{
    border-spacing: 0;
}
th,td{
    padding: 8px 16px;
    border: 1px solid #e9e9e9;
    text-align: left;
}
th{
    background-color: #f7f7f7;
    color: #5c6b77;
    font-weight: 600;
}
js
 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
let app = new Vue({
        infos: [
            {"name": "算法导论", "date": "2006-9", "count": 1, "price": 85},
            {"name": "编程艺术", "date": "2006-2", "count": 1, "price": 59},
            {"name": "编程珠玑", "date": "2008-10", "count": 1, "price": 39},
            {"name": "代码大全", "date": "2006-3", "count": 1, "price": 128},
        ],

    },
    methods: {
        add(item) {
            console.log("add")
           item.count++
        },
        sub(item) {
           item.count--
        },
        removeLine(index) {
            this.infos.splice(index, 1)
        }
    },
    filters: {
        formatPrice(price) {
            return "¥ " + price.toFixed(2)
        }
    },
    computed: {
        totalPrice() {
            let totalPriceSum = 0
            for (let info of this.infos) {
                totalPriceSum += info.count * info.price
            }
            return totalPriceSum
        }
    }
})

组件化开发

认识组件化

什么是组件化

组件化是讲一个页面进行拆分为一个一个小的功能块,每个功能块完成对应的功能,如下图。

_images/模块化.png

组件化的思想

  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。

  • 任何的应用都会被抽象成一颗组件树。

注册组件

基本步骤

组件的注册分如下3个阶段

  1. 创建组件构造器

  2. 注册组件

  3. 使用组件

注册代码图

_images/组件步骤.png
  1. 其中调用Vue.extend()创建的是一个组件构造器。

  2. 调用Vue.component()是将刚才的组件构造器注册为一个组件。

  3. 组件必须挂载在某个Vue实例下,否则它不会生效。

详细代码实现

 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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!--   使用-->
    <demo-cpt></demo-cpt>
    <demo-cpt></demo-cpt>
    <demo-cpt></demo-cpt>

</div>
<script src="../js/vue.js"></script>
<script>
    // 创建
    const demoCpt = Vue.extend(
        {
            template: `
            <div>
                <h2> 组件标题</h2>
                <p> 组件内容</p>
            </div>
            `
        }
    )
    // 注册
    Vue.component("demo-cpt", demoCpt)
    let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        }
    })
</script>
</body>
</html>

组件其他补充

全局组件

通过Vue.component()注册的组件为全局的组件。意味这个组件是可以全局使用的。

Vue.component("demo-cpt",demoCpt)

局部组件

如果在特定的vue下的components属性指定的组件为局部组件,只能在特定的父组件使用的。

let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        },
        components:{
            "demo-cpt2": demoCpt2
        }
    })

父子组件

组件和组件是有一定的层次关系的, 其中其中父子组件的是而非常重要的关系。

_images/父子组件.png

代码如下:

 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
54
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <div id="app">
        <!--    使用-->
        <demo-cpt2>
            <demo-cpt></demo-cpt>
        </demo-cpt2>


    </div>
    <script src="../js/vue.js"></script>
    <script>
        // 创建
        const demoCpt = Vue.extend({
            template: `
            <div>
                <h2> 组件标题</h2>
            </div>
            `
        })
        const demoCpt2 = Vue.extend({
            template: `
            <div>
                <h2> 组件标题2</h2>
                <p>haha</p>
                <demo-cpt></demo-cpt>
                <p>haha</p>
            </div>
            `,
            components: {
                "demo-cpt": demoCpt
            }
        })

        let app = new Vue({
            el: "#app",
            data: {
                cnt: 1,
            },
            components: {
                "demo-cpt2": demoCpt2
            }
        })
    </script>
</body>

</html>

模块的分离写法

上面我们可以看到写一个组件内部还包含了html的代码,非常不方便管理和维护。可以通过如下方式进行改造。

2中方式在代码中体现:

 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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!--    使用-->

    <demo-cpt></demo-cpt>
    <demo-cpt2></demo-cpt2>

</div>


<script src="../js/vue.js"></script>

<script type="text/x-template" id="demoCpt">
    <div>
        <h2> 组件标题</h2>
    </div>
</script>

<template  id="demoCpt2">
    <div>
        <h2> 组件标题</h2>
    </div>
</template>


<script>

    // 创建
    Vue.component('demo-cpt',
        {
            template: '#demoCpt'
        }
    )
    Vue.component('demo-cpt2',
        {
            template: '#demoCpt2'
        }
    )
    let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        },
    })
</script>
</body>
</html>

组件数据存放

组件内的数据有个data属性,但是这个是一个函数的,通过这个函数返回一个dict对象即可。

详细代码如下:

 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
54
55
56
57
58
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
<demo-cpt></demo-cpt>
</div>


<script src="../js/vue.js"></script>


<template  id="demoCpt">
    <div>
       <button @click="sub">-</button>
            {{count }}
        <button @click="add">+</button>
    </div>
</template>


<script>

    // 创建
    Vue.component('demo-cpt',
        {
            template: '#demoCpt',
            data(){
                // 组件是复用的,保障每组件实例对象是有独立的数据地址空间的。使用函数解决。
                return {
                    count: 1
                }

            },
            methods:{
                add(){
                    return this.count++
                },
                sub(){
                    return this.count--
                }

            }
        }
    )

    let app = new Vue({
        el: "#app",
        data: {
            cnt: 1,
        },
    })
</script>
</body>
</html>

Note

组件的data必须是一个函数的,不能是通过的字典,因为我们组件是复用的,组件复用后的数据一定是独立的。

父子组件通信

官方文档中给出了父子组件的通信方式。

  • 通过props向子组件传递数据

  • 通过事件向父组件发送消息

_images/父子通信.png

父级向子级传递

父组件向子组件创建数据,可以通过子组件提供props来传递。参考如下:

 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
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <label>
        <input type="text" v-model="t1"> 第1个组件的值
    </label>
    <label>
        <input type="text" v-model="t2"> 第2个组件的值
    </label>
    <!--    使用-->
    <label> 第一个组件实例</label>
    <demo-cpt :title="t1"></demo-cpt>
    <label> 第2个组件实例</label>
    <demo-cpt :title="t2"></demo-cpt>

</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
        <h2>{{title}}</h2>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
        props: {
            "title": {
                type: String,
                default: "default title"
            }
        },
        data() {

            return {
            }
        },

    }
    let app = new Vue({
        el: "#app",
        data: {
           t1: "abc",
            t2: "def",
        },
        components: {
            "demo-cpt": demoCpt
        },
        methods: {

        }

    })
</script>
</body>
</html>

子级向父级传递

自组件向父组件传递数据,通过发射事件,然后父组件绑定事件即可。参考如下:

 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">



    <!--    使用-->
    <label> 第一个组件实例</label>
    <demo-cpt @item-click="getSubInfo" ></demo-cpt>

    <label >从子组件获取的值</label>
    <h2> {{ subInfo}}</h2>

</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
       <button v-for="item in categories" @click="bntClick(item)"> {{item.name }}</button>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
        props: {
            "title": {
                type: String,
                default: "default title"
            }
        },
        data() {

            return {
                categories:[
                    {id:"123","name":"热门推荐"},
                    {id:"124","name":"手机数码"},
                    {id:"125","name":"电脑办公"},
                    {id:"126","name":"家用家电"},
                ]
            }
        },
        methods: {
            bntClick(item) {
                console.log(item)
                this.$emit("item-click",item)
            }
        }

    }
    let app = new Vue({
        el: "#app",
        data: {
            subInfo: {}
        },
        components: {
            "demo-cpt": demoCpt
        },
        methods: {
            getSubInfo(item){
                this.subInfo= item.name
                console.log(item)
            }

        },


    })
</script>
</body>
</html>

父访问子组件数据

父组件访问子组件:使用$children或$refs

 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
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <button @click="getSubInfo">点击展示子组件信息</button>
    <demo-cpt ref="aaa"></demo-cpt>

</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
       <h2>{{title}}</h2>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
        props: {
            "title": {
                type: String,
                default: "default title"
            }
        },
        methods: {
            showMessage(){
                //console.log(this.title)
                alert(this.title)
            }
        }


    }
    let app = new Vue({
        el: "#app",
        data: {

        },
        components: {
            "demo-cpt": demoCpt
        },
        methods: {
            getSubInfo(){
               // console.log(this.$children)
                this.$refs["aaa"].showMessage()
            }

        },


    })
</script>
</body>
</html>

子访问父组件数据

子组件访问父组件:使用$parent

 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
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <button @click="getSubInfo">点击展示子组件信息</button>
    <demo-cpt ref="aaa"></demo-cpt>

</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
       <h2>{{title}}</h2>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
        props: {
            "title": {
                type: String,
                default: "default title"
            }
        },
        methods: {
            showMessage(){
                //console.log(this.title)
                alert(this.title)
            }
        }


    }
    let app = new Vue({
        el: "#app",
        data: {

        },
        components: {
            "demo-cpt": demoCpt
        },
        methods: {
            getSubInfo(){
               // console.log(this.$children)
                this.$refs["aaa"].showMessage()
            }

        },


    })
</script>
</body>
</html>

插槽slot

编译作用域

父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

为什么使用slot

  • 组件的插槽也是为了让我们封装的组件更加具有扩展性。

  • 让使用者可以决定组件内部的一些内容到底展示什么。

slot的基本使用

在组件的模板定义中引入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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">

    <demo-cpt>
        <button>haha</button>
    </demo-cpt>
    <demo-cpt>
        <h2>abc</h2>
        <h2>abc</h2>
        <h2>abc</h2>
    </demo-cpt>
    <demo-cpt></demo-cpt>

</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
        <h2>测试</h2>
        <slot>
            <button>默认button</button>
        </slot>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
    }
    let app = new Vue({
        el: "#app",
        data: {
            "name": "panda"
        },
        components: {
            "demo-cpt": demoCpt
        },
    })
</script>
</body>
</html>

具名slot

当子组件的功能复杂时,子组件的插槽可能并非是一个,怎么方便控制用户想替换哪个slot?

这就需要给slot起个名字,让用户选择给那个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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">

    <demo-cpt>
      <span slot="left">返回</span>
    </demo-cpt>


</div>
<script src="../js/vue.js"></script>

<template id="demoCpt">
    <div>
        <slot name="left"></slot>
        <slot name="center"></slot>
        <slot name="right"></slot>
    </div>
</template>


<script>

    const demoCpt = {
        template: "#demoCpt",
    }
    let app = new Vue({
        el: "#app",
        data: {
            "name": "panda"
        },
        components: {
            "demo-cpt": demoCpt
        },
    })
</script>
</body>
</html>

模块化

为什么需要模块化

起初js只是完成一些简单的脚本处理,随着ajax的出现,慢慢形成了前后端分离的阶段。 前段完成工作越来越多,代码被组织在多个js文件中,维护和管理是个严重的问题。

需要解决2个问题

  • 复用性

  • 可维护性

使用模块作为出口的规范

CommonJS

commonJS服务器端(nodeJS)的js模块规范,同步加载方式。

ADM

AMD是requireJS倡导的一种模块化规范,推崇依赖前置;在requireJS中模块是通过define来进行定义的,如果模块之间相互依赖,需要先将依赖模块导入进来,待导入完毕之后,在通过回调函数的方式执行后面的代码,有效的解决了模块依赖的问题。

ES6Moudle

使用import/export语法,在文件顶部导入需要的模块,特点是:静态化

导出样例

CommonJS导出

1
2
3
4
5
6
7
// 导出
module.exports = {
    flag: flag,
    max: function (a,b){
        return a>b ? a:b
    }
}

CommonJS导入

1
2
var max =  require("./01-模块化开发导出")
max(1,2)

ES6导出

1
2
3
4
5
6
7
8
9
let name='xiaoming'
let sum = function (a,b){
    return a+b
}


export {
    name,sum
}

Tip

text 某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名, 使用export default <object>

ES6导入

1
2
3
4
5
import {name,sum}  from "./xiaohong"


let c = sum(1,2)
console.log(c )

webpack

认识webpack

什么是webpack

webpack是一个现代的JavaScript应用的静态模块打包工具。

功能

  • 将webpack中的各种资源模块进行打包合并成一个或多个包(Bundle)。

  • 对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

webpack和grunt/gulp的对比

  • grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。

  • webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。

_images/打包.png

webpack的安装

前提环境是需要node的,然后需要有npm的, 最后通过npm安装webpack

npm install webpack --save-dev

其中 –save-dev 是表示开发时依赖的。

webpack的起步

目录说明

dist

用于存放打包后的文件,也就是后续我们生产环境需要的文件夹,其他的生产环境不需要。

src

源码文件夹,用于存放我们的开发文件。

index.html

首页文件

package.json

通过npm init生成的文件,

_images/webpack起步.png

通过如下命令可以完成打包

# npm初始化
npm init
# 安装webpack
npm install webpack --save-dev
# 进行打包操作
webpack bundle  --entry  ./src/main.js -o ./dist/bundle.js

Tip

详细的具体代码点击右上角的github进入这个仓库找到工程进行测试。

webpack的配置

上面就是手工打包的一种方式了, 但是每次都要敲个命令去执行显然不是很方便的, 需要写成脚本方式的,然后执行才是正确做法。

webpack提供一个机制,可以配置一个文件,然后直接执行webpack 即可完成构建。

webpack.config.js样例

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    }
};

package.json 样例

这个文件可以先通过npm init进行初始化,然后修改为如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "name": "webpackconfig",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo ok ",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^5.0.1",
    "mini-css-extract-plugin": "^1.3.3",
    "style-loader": "^2.0.0",
    "ts-loader": "^8.0.13",
    "webpack": "^5.11.1"
  }
}

构建

上面的2个文件都创建和修改完毕后, 我们执行`npm run build` 就会从package.json文件找到`build`对应的脚本`webpack`进行执行,webpack在执行的时候会读取`webpack.config.js`作为配置文件 进行构建。这样就构建起来非常方便了。

loader的使用

上面的构建我们webpack完成了js的文件构建打包,但是文件还有其他的css,html等,这些文件webpack本身是无法进行处理的,需要借助loader完成处理。

loader使用过程需要2个步骤。

  1. 通过npm安装需要使用的loader

  2. 在webpack.config.js中的modules关键字下进行配置

css文件处理

css的处理需要相关的css load 支持需要先安装对应的loader, 然后进行配置。

安装loader

进行配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
const path = require('path');
//const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    {loader: "style-loader"},
                    {loader: "css-loader"}
                ]
            }
        ]
    },
};

less文件处理

还是按照软件和对应的配置

npm install --save-dev less-loader less
 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
const path = require('path');

//const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            // {
            //
            //     test: /\.css$/,
            //     use: [
            //         {loader: "less-loader"},
            //         { loader:"style-loader" },
            //         { loader:"css-loader" }
            //     ]
            //
            // },
            {
                test: /\.less$/,
                use: [
                    {loader: "less-loader"},
                    { loader:"style-loader" },
                    { loader:"css-loader" }
                ]
            },
        ]
    },


};

webpack中配置Vue

安装loader

npm install --save-dev vue-loader vue-template-compiler

进行配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const path = require('path')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
}

plugin的使用

插件是完成额外的附属的一些功能,比如添加版权信息。

 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
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');
//"html-webpack-plugin": "^3.2.0",
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
  },
  module: {
    rules: [

      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  plugins:[
    new webpack.BannerPlugin({
      banner: `
      auth: zhaojiedi1992
      email: zhaojiedi1992@outlook.com
      protal: mit
      `
    }),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
}

搭建本地服务器

webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。

安装包

npm install --save-dev webpack-dev-server

配置

 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
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');
//"html-webpack-plugin": "^3.2.0",
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
  },
  module: {
    rules: [

      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },

  plugins:[
    new webpack.BannerPlugin({
      banner: `
      auth: zhaojiedi1992
      email: zhaojiedi1992@outlook.com
      protal: mit
      `
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      title: "app"
    })
  ],
  devServer:{
    contentBase: path.join(__dirname, 'dist'),
    compress: false ,
    port: 9000
  }
}

router

router 基本使用

router是完成前端路由的。基本使用如下。

 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
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import About from '@/components/About'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: "/home"
    },
    {
      path: '/home',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ],
  mode: 'history'
})

完成跳转

可以在组件内的一些方法中完成一些调整。

 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
<template>
  <div id="app">

    <router-link to="/home" tag="button"  >home</router-link>
    <router-link to="/about" tag="button"  >about</router-link>
    <button @click="aboutClick">about2</button>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    aboutClick(){
      this.$router.push("/about")
     // history.pushState("about")
    },
  }
}
</script>

<style>
.router-link-active{
  color: red;
}
</style>

动态路由

router是完成前端路由的。基本使用如下。

 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
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import About from '@/components/About'
import User from '@/components/User'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: "/home"
    },
    {
      path: '/home',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    },
    // {
    //   path: '/user',
    //   name: 'user',
    //   component: User
    // },
    {
      path: '/user/:uid',
      name: 'user',
      component: User
    }
  ],
  mode: 'history'
})

懒加载

router是完成前端路由的。基本使用如下。

 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
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '@/components/Home'
// import About from '@/components/About'


const Home = () => import ('@/components/Home')
const About = () => import ('@/components/About')

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: "/home"
    },
    {
      path: '/home',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ],
  mode: 'history'
})

嵌套路由

router是完成前端路由的。基本使用如下。

 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
import Vue from 'vue'
import Router from 'vue-router'
// import Home from '@/components/Home'
// import About from '@/components/About'

const Home = () => import ('@/components/Home')
const About = () => import ('@/components/About')

const HomeNews = () => import ('@/components/HomeNews')
const HomeMessages = () => import ('@/components/HomeMessages')

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '',
      redirect: "/home",

    },
    {
      path: '/home',
      name: 'home',
      component: Home,
      children:[
        {
          path: '',
          redirect: "news",
        },
        {
          path: 'news',
          component: HomeNews
        },
        {
          path: 'messages',
          component: HomeMessages
        }
      ],
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ],
  mode: 'history'
})

参数传递

router是完成前端路由的。基本使用如下。

 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
<template>
<div>
  <h2>我是Profile</h2>
  <p>我是Profile内容</p>
  <p>第一种方式获取传递过来的uid为: {{Uid}}</p>
  <p>第二种方式获取传递过来的uid为: {{Uid2}}</p>

</div>
</template>

<script>
export default {
name: "Profile",
  computed:{
    Uid(){
      return this.$route.params.uid
    },
    Uid2(){
      return this.$route.query.uid
    }
  }
}
</script>

<style scoped>

</style>
 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
<template>
  <div id="app">

    <router-link to="/home">home</router-link>
    <router-link to="/about">about</router-link>
    <router-link :to="UidUri">user</router-link>
    <router-link :to="{path: '/profile', query:{uid: 'panda2'}}">Profile</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      uid: 'panda'
    }
  },
  computed: {
    UidUri() {
      return "/user/" + this.uid

    }
  }
}
</script>

<style>

</style>

vuex详解

vuex 基本使用

通过vuex可以存储一些公共数据,方便整体系统进行使用和操作。

 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
import Vue from 'vue'
import Vuex from 'vuex'


Vue.use(Vuex)


const store = new Vuex.Store({
  state: {
    counter:10000
  },
  mutations: {
    add(state){
      state.counter +=1
    },
    sub(state){
      state.counter-=1
    }
  },
  actions: {},
  getters: {},
  modules: {},
})

export default store

vuex getter

getter 类似组件的属性,不会每次获取的时候都进行计算。

 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
import Vue from 'vue'
import Vuex from 'vuex'


Vue.use(Vuex)


const store = new Vuex.Store({
  state: {
    counter:10000,
    students:[
      {id:1,firstName:"jiedi01", secondName: "zhao",age:21,height:165},
      {id:2,firstName:"jiedi02", secondName: "zhao",age:22,height:170},
      {id:3,firstName:"jiedi03", secondName: "zhao",age:25,height:175},
      {id:4,firstName:"jiedi04", secondName: "zhao",age:30,height:180},
    ]

  },
  mutations: {
    add(state){
      state.counter +=1
    },
    sub(state){
      state.counter-=1
    }
  },
  actions: {},
  getters: {
    powerCounter(state){
      return  state.counter * state.counter
    },
    ageMore25Count(state){
      return state.students.filter(student=>student.age>=25).length
    },
    StudentById(state){
      // 这是返回一个函数, 参数是接受一个参数的
      // 好理解的写法
      // let infoByid=function (id){
      //   return state.students.find(s=>s.id===id)
      // }
      // return infoByid

      // 简写的写法
      return (id)=>state.students.find(s=>s.id===id)

    }
  },
  modules: {},
})

export default store

vuex mutation

mutation 可以做一些同步操作,方便使用dev工具进行前段调整。 .. literalinclude:: ../../中级学习/07-vuex/02-vuexlearn-mutation/store/index.js

encoding

utf-8

language

javascript

emphasize-lines

1

linenos

vuex action

mutation 可以做一些同步操作,有些异步操作,就需要action了, 然后action操作mutation可以跟着变化。

vuex module

module是可以做多个模块的, 方便管理

vuex 文件拆解

随着项目越来越大, 单个index.js不太方便文件管理的,需要进行拆分管理。

ls -1  中级学习/07-vuex/06-vuexlearn-文件拆解/store/

actions.js
getters.js
index.js
modules
mutations.js
state.js

网络封装

axios

基本使用

get使用

config使用

并发使用

实例使用

项目实战

测试项目实战

项目部署

原理详解