🍑Vue-Study

 


视频地址:https://www.bilibili.com/video/BV17h41137i4

课件链接:https://pan.baidu.com/s/1OQJdnVR74_SBr7BqUYQAbw?pwd=8023

Vue2官网:https://v2.cn.vuejs.org/

Vue3官网:https://cn.vuejs.org/

代码:

Vue-基础部分

前言:环境准备

VsCode插件:

  • techer.open-in-browser
  • ritwickdey.LiveServer

Chrom浏览器插件:

 1.1、Vue程序初体验

1.1.1、第一个Vue程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
 
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=, initial-scale=1.0">
    <title>Document</title>
</head>
 
<body>
    <!--安装vue -->
    <script src="../js/vue.js"></script>
    <div id="app"></div>
    <script>
        let myVue = new Vue({
            template: "<h1>hello Vue</h1>"
        });
        myVue.$mount('#app');
    </script>
</body>
</html>

 1.1.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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板引擎数据来源</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <!-- 模板语句的数据来源:
            1. 谁可以给模板语句提供数据支持呢?data选项。
            2. data选项的类型是什么?Object | Function (对象或者函数)
            3. data配置项的专业叫法:Vue 实例的数据对象.(data实际上是给整个Vue实例提供数据来源的。)
            4. 如果data是对象的话,对象必须是纯粹的对象 (含有零个或多个的 key/value 对)
            5. data数据如何插入到模板语句当中?
                {{}} 这是Vue框架自己搞的一套语法,别的框架看不懂的,浏览器也是不能够识别的。
                Vue框架自己是能够看懂的。这种语法在Vue框架中被称为:模板语法中的插值语法。(有的人把他叫做胡子语法。)
                怎么用?
                    {{data的key}}
                插值语法的小细节:
                    {这里不能有其它字符包括空格{
                    }这里不能有其它字符包括空格}       
     -->
    <div id="app"></div>
 
    <script>
        let myVue = new Vue({
            template:
                    `
                        <h1>{{name}},年龄是:{{age}},兴趣爱好是:{{hoppy[0]}}、{{hoppy[1]}}、{{hoppy[2]}}</h1>
                    `,
            data: {
                name: "zhangsan",
                "age": "23",
                "hoppy": [
                    "抽烟", "喝酒", "烫头"
                ]
            }
        });
        myVue.$mount("#app");
    </script>
</body>
 
</html>

1.1.3、template配置项详解

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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>template配置项详解</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <div>
            <h1>姓名:{{name}}</h1>
            <h1>年龄:{{age}}</h1>
        </div>
    </div>
 
    <script>
        // Vue.config是Vue的全局配置对象。
        // productionTip属性可以设置是否生成生产提示信息。
        // 默认值:true。如果是false则表示阻止生成提示信息。
        //Vue.config.productionTip = false
        // 或者直接在vue.js全局搜索:productionTip,将它设置为false
        /*
            一 、关于template配置项:
                1.template后面指定的是模板语句,但是模板语句中只能有一个根节点。
                2.只要data中的数据发生变化,模板语句一定会重新编译。(只要data变,template就会重新编译,重新渲染)
                3.如果使用template配置项的话,指定挂载位置的元素会被替换。
                4.好消息:目前我们可以不使用template来编写模板语句。这些模板语句可以直接写到html标签中。Vue框架能够找到并编译,然后渲染。
                5.如果直接将模板语句编写到HTML标签中,指定的挂载位置就不会被替换了。
            二、关于$mount('#app')?
                也可以不使用$mount('#app')的方式进行挂载了。
                在Vue中有一个配置项:el
                el配置项和$mount()可以达到同样的效果。
                el配置项的作用?
                    告诉Vue实例去接管哪个容器。
                    el : '#app',表示让Vue实例去接管id='app'的容器。
                el其实是element的缩写。被翻译为元素。
        */
        new Vue({
            data: {
                name: "zhangzhixi",
                age: "23"
            },
            // 替换掉 .$mount()
            el: "#app"
        });
    </script>
</body>
</html>

1.1.4、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
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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue实例 和 容器 的关系是:一夫一妻制</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备容器 -->
    <div class="app">
        <h1>{{msg}}</h1>
    </div>
 
    <div class="app">
        <h1>{{msg}}</h1>
    </div>
 
    <!-- 准备容器 -->
    <div id="app2">
        <h1>{{name}}</h1>
    </div>
 
    <!-- vue程序 -->
    <script>
        /*
            验证:一个Vue实例可以接管多个容器吗?
                不能。一个Vue实例只能接管一个容器。一旦接管到容器之后,即使后面有相同的容器,Vue也是不管的。因为Vue实例已经“娶到媳妇”了。
        */
        new Vue({
            el : '.app',
            data : {
                msg : 'Hello Vue!'
            }
        })
 
        new Vue({
            el : '#app2',
            data : {
                name : 'zhangsan'
            }
        })
 
        // 这个Vue实例想去接管 id='app2'的容器,但是这个容器已经被上面那个Vue接管了。他只能“打光棍”了。
        new Vue({
            el : '#app2',
            data : {
                name : 'jackson'
            }
        })
         
    </script>
 
 
</body>
</html>

1.2、核心技术

1.2.1、模板语法之插值语法

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
79
80
81
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板语法之插值语法{{}}</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        主要研究:{{这里可以写什么}}
        1. 在data中声明的变量、函数等都可以。
        2. 常量都可以。
        3. 只要是合法的javascript表达式,都可以。
        4. 模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 等。
            'Infinity,undefined,NaN,isFinite,isNaN,'
            'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,'
            'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,'
            'require'
     -->
    <!-- 准备容器 -->
    <div id="app">
        <!-- 在data中声明的 -->
        <!-- 这里就可以看做在使用msg变量。 -->
        <h1>{{msg}}</h1>
        <h1>{{sayHello()}}</h1>
        <!-- <h1>{{i}}</h1> -->
        <!-- <h1>{{sum()}}</h1> -->
 
        <!-- 常量 -->
        <h1>{{100}}</h1>
        <h1>{{'hello vue!'}}</h1>
        <h1>{{3.14}}</h1>
 
        <!-- javascript表达式 -->
        <h1>{{1 + 1}}</h1>
        <h1>{{'hello' + 'vue'}}</h1>
        <h1>{{msg + 1}}</h1>
        <h1>{{'msg' + 1}}</h1>
        <h1>{{gender ? '男' : '女'}}</h1>
        <h1>{{number + 1}}</h1>
        <h1>{{'number' + 1}}</h1>
        <h1>{{msg.split('').reverse().join('')}}</h1>
 
        <!-- 错误的:不是表达式,这是语句。 -->
        <!-- <h1>{{var i = 100}}</h1> -->
 
        <!-- 在白名单里面的 -->
        <h1>{{Date}}</h1>
        <h1>{{Date.now()}}</h1>
        <h1>{{Math}}</h1>
        <h1>{{Math.ceil(3.14)}}</h1>
 
    </div>
 
    <!-- vue程序 -->
    <script>
 
        // 用户自定义的一个全局变量
        var i = 100
        // 用户自定义的一个全局函数
        function sum(){
            console.log('sum.....');
        }
 
        new Vue({
            el : '#app',
            data : {
                number : 1,
                gender : true,
                msg : 'abcdef',  // 为了方便沟通,以后我们把msg叫做变量。(这行代码就可以看做是变量的声明。)
                sayHello : function(){
                    console.log('hello vue!');
                }
            }
        })
    </script>
</body>
</html>

 1.2.2、模板语法之指令:v-once(只执行一次)

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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板语法之指令语法 v-??? </title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <!--
        指令语法:
            1. 什么是指令?有什么作用?
                指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
            2. Vue框架中的所有指令的名字都以“v-”开始。
            3. 插值是写在标签体当中的,那么指令写在哪里呢?
                Vue框架中所有的指令都是以HTML标签的属性形式存在的,例如:
                    <span 指令是写在这里的>{{这里是插值语法的位置}}</span>
                    注意:虽然指令是写在标签的属性位置上,但是这个指令浏览器是无法直接看懂的。
                    是需要先让Vue框架进行编译的,编译之后的内容浏览器是可以看懂的。
            4. 指令的语法规则:
                指令的一个完整的语法格式:
                    <HTML标签 v-指令名:参数="javascript表达式"></HTML标签>
                    表达式:
                        之前在插值语法中{{这里可以写什么}},那么指令中的表达式就可以写什么。实际上是一样的。
                        但是需要注意的是:在指令中的表达式位置不能外层再添加一个{{}}
                    不是所有的指令都有参数和表达式:
                        有的指令,不需要参数,也不需要表达式,例如:v-once
                        有的指令,不需要参数,但是需要表达式,例如:v-if="表达式"
                        有的指令,既需要参数,又需要表达式,例如:v-bind:参数="表达式"
            5. v-once 指令
                作用:只渲染元素一次。随后的重新渲染,元素及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
             
            6. v-if="表达式" 指令
                作用:表达式的执行结果需要是一个布尔类型的数据:true或者false
                    true:这个指令所在的标签,会被渲染到浏览器当中。
                    false:这个指令所在的标签,不会被渲染到浏览器当中。
     -->
    <!-- 准备一个容器 -->
    <div id="app">
        <h1>{{msg}}</h1>
        <h1 v-once>{{msg}}</h1>
        <h1 v-if="a > b">v-if测试:{{msg}}</h1>
    </div>
    <!-- vue程序 -->
    <script>
        new Vue({
            el: '#app',
            data: {
                msg: 'Hello Vue!',
                a: 12,
                b: 11
            }
        })
    </script>
</body>
 
</html>

用Vue插件,修改文本

1.2.2、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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-bind指令详解(它是一个负责动态绑定的指令)</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        v-bind指令详解
            1. 这个指令是干啥的?
                它可以让HTML标签的某个属性的值产生动态的效果。
            2. v-bind指令的语法格式:
                <HTML标签 v-bind:参数="表达式"></HTML标签>
            3. v-bind指令的编译原理?
                编译前:
                    <HTML标签 v-bind:参数="表达式"></HTML标签>
                编译后:
                    <HTML标签 参数="表达式的执行结果"></HTML标签>
                注意两项:
                    第一:在编译的时候v-bind后面的“参数名”会被编译为HTML标签的“属性名”
                    第二:表达式会关联data,当data发生改变之后,表达式的执行结果就会发生变化。
                    所以,连带的就会产生动态效果。
            4. v-bind因为很常用,所以Vue框架对该指令提供了一种简写方式:
                只是针对v-bind提供了以下简写方式:
                    <img :src="imgPath">
             
            5. 什么时候使用插值语法?什么时候使用指令?
                凡是标签体当中的内容要想动态,需要使用插值语法。
                只要向让HTML标签的属性动态,需要使用指令语法。
     -->
    <!-- 准备一个容器 -->
    <div id="app">
        <!-- 注意:以下代码中 msg 是变量名。 -->
        <!-- 注意:原则上v-bind指令后面的这个参数名可以随便写。 -->
        <!-- 虽然可以随便写,但大部分情况下,这个参数名还是需要写成该HTML标签支持的属性名。这样才会有意义。 -->
        <span v-bind:xyz="msg"></span>
 
        <!-- 这个表达式带有单引号,这个'msg'就不是变量了,是常量。 -->
        <span v-bind:xyz="'msg'"></span>
 
        <!-- v-bind实战 -->
        <img src="../img/1.jpg"> <br>
        <img v-bind:src="imgPath"> <br>
 
        <!-- v-bind简写形式 -->
        <img :src="imgPath"> <br>
 
        <!-- 这是一个普通的文本框 -->
        <input type="text" name="username" value="zhangsan"> <br>
        <!-- 以下文本框可以让value这个数据变成动态的:这个就是典型的动态数据绑定。 -->
        <input type="text" name="username" :value="username"> <br>
 
        <!-- 使用v-bind也可以让超链接的地址动态 -->
        <a href="https://www.baidu.com">走起</a> <br>
        <a :href="url">走起2</a> <br>
 
        <!-- 不能采用以下写法吗? -->
        <!--
            不能这样,报错了,信息如下:
            Interpolation inside attributes has been removed.
            Use v-bind or the colon shorthand instead. For example,
            instead of <div id="{{ val }}">, use <div :id="val">
             
            属性内部插值这种语法已经被移除了。(可能Vue在以前的版本中是支持这种写法的,但是现在不允许了。)
            请使用v-bind或冒号速记来代替。
            请使用 <div :id="val"> 来代替 <div id="{{ val }}">
 
         -->
        <!-- <a href="{{url}}">走起3</a>  -->
 
        <h1>{{msg}}</h1>
 
    </div>
    <!-- vue程序 -->
    <script>
         
        // 赋值的过程就可以看做是一种绑定的过程。
        //let i = 100
 
        new Vue({
            el : '#app',
            data : {
                msg : 'Hello Vue!',
                imgPath : '../img/1.jpg',
                username : 'jackson',
                url : 'https://www.baidu.com'
            }
        })
    </script>
</body>
</html>

1.2.3、v-model指令详解

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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-model指令详解</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        v-bind和v-model的区别和联系
            1. v-bind和v-model这两个指令都可以完成数据绑定。
            2. v-bind是单向数据绑定。
                data ===> 视图
            3. v-model是双向数据绑定。
                data <===> 视图
            4. v-bind可以使用在任何HTML标签当中。v-model只能使用在表单类元素上,例如:
                input标签、select标签、textarea标签。
                为什么v-model的使用会有这个限制呢?
                    因为表单类的元素才能给用户提供交互输入的界面。
                v-model指令通常也是用在value属性上面的。
            5. v-bind和v-model都有简写方式:
                v-bind简写方式:
                    v-bind:参数="表达式"    简写为      :参数="表达式"
                v-model简写方式:
                    v-model:value="表达式"  简写为      v-model="表达式"
     -->
    <!-- 准备一个容器 -->
    <div id="app">
        v-bind指令:<input type="text" v-bind:value="name1"><br>
        v-model指令:<input type="text" v-model:value="name2"><br>
 
        <!-- 以下报错了,因为v-model不能使用在这种元素上。 -->
        <!-- <a v-model:href="url">百度</a> -->
 
        v-bind指令:<input type="text" :value="name1"><br>
        v-model指令:<input type="text" v-model="name2"><br>
 
        消息1:<input type="text" :value="msg"><br>
        消息2:<input type="text" v-model="msg"><br>
    </div>
 
    <!-- vue程序 -->
    <script>
        new Vue({
            el : '#app',
            data : {
                name1 : 'zhangsan',
                name2 : 'wangwu',
                url : 'https://www.baidu.com',
                msg : 'Hello Vue!'
            }
        })
    </script>
</body>
</html>

1.2.4、MVVM分层思想

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>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>初识MVVM分层思想</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        1. MVVM是什么?
            M:Model(模型/数据)
            V:View(视图)
            VM:ViewModel(视图模型):VM是MVVM中的核心部分。(它起到一个核心的非常重要的作用。)
            MVVM是目前前端开发领域当中非常流行的开发思想。(一种架构模式。)
            目前前端的大部分主流框架都实现了这个MVVM思想,例如Vue,React等。
        2. Vue框架遵循MVVM吗?
            虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。
            Vue框架基本上也是符合MVVM思想的。
 
        3. MVVM模型当中倡导了Model和View进行了分离,为什么要分离?
            假如Model和View不分离,使用最原始的原生的javascript代码写项目:
                如果数据发生任意的改动,接下来我们需要编写大篇幅的操作DOM元素的JS代码。
 
            将Model和View分离之后,出现了一个VM核心,这个VM把所有的脏活累活给做了,
            也就是说,当Model发生改变之后,VM自动去更新View。当View发生改动之后,
            VM自动去更新Model。我们再也不需要编写操作DOM的JS代码了。开发效率提高了很多。
     -->
     <!-- 准备容器 -->
     <!-- View V-->
     <div id="app">
        姓名:<input type="text" v-model="name">
     </div>
 
     <!-- vue程序 -->
     <script>
        // ViewModel  VM
        const vm = new Vue({
            el : '#app',
            // Model  M
            data : {
                name : 'zhangsan'
            }
        })
     </script>
</body>
</html>

 1.2.5、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
39
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue数据代理机制对属性名的要求</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        1. Vue实例不会给以_和$开始的属性名做数据代理。
         
        2. 为什么?
            如果允许给_或$开始的属性名做数据代理的话。
            vm这个Vue实例上可能会出现_xxx或$xxx属性,
            而这个属性名可能会和Vue框架自身的属性名冲突。
 
        3. 在Vue当中,给data对象的属性名命名的时候,不能以_或$开始。
     -->
    <!-- 容器 -->
    <div id="app">
        <h1>{{msg}}</h1>
    </div>
    <!-- vue程序 -->
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Hello Vue!',
                /* 不能被识别 */
                _name : 'zhangsan',
                $age : 20
            }
        })
    </script>
</body>
</html>

1.2.6、解读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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>解读Vue框架源代码</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <!--
        Vue框架源代码中关键性代码:
        1. var data = vm.$options.data;
            注意:这是获取data。程序执行到这里的时候vm上还没有 _data 属性。
        2. data = vm._data = isFunction(data) ? getData(data, vm) : data || {};
            程序执行完这个代码之后,vm对象上多了一个_data这样的属性。
            通过以上源码解读,可以得知data不一定是一个{},也可以是一个函数。
            代码含义:
                如果data是函数,则调用getData(data, vm)来获取data。
                如果data不是函数,则直接将data返回,给data变量。并且同时将data赋值给vm._data属性了。
            有一个疑问?
                程序执行到这里,为什么要给vm扩展一个_data属性呢?
                    _data属性,以"_"开始,足以说明,这个属性是人家Vue框架底层需要访问的。
                    Vue框架底层它使用vm._data这个属性干啥呢?
                        vm._data是啥?
                            vm._data 是:{
                                            name : 'jackson',
                                            age : 35
                                        }
                vm._data 这个属性直接指向了底层真实的data对象。通过_data访问的name和age是不会走数据代理机制的。
                通过vm._data方式获取name和age的时候,是不会走getter和setter方法的。
             
            注意:对于Vue实例vm来说,不仅有_data这个属性,还有一个$data这个属性。
                   _data 是框架内部使用的,可以看做私有的。
                   $data 这是Vue框架对外公开的一个属性,是给我们程序员使用。
 
        3. 重点函数:
            function isReserved(str) {
                var c = (str + '').charCodeAt(0);
                return c === 0x24 || c === 0x5f;
            }
            这个函数是用来判断字符串是否以 _ 和 $ 开始的。
            true表示以_或$开始的。
            false表示不是以_或$开始的。
        4. proxy(vm, "_data", key);
            通过这行代码直接进入代理机制(数据代理)。
        5. 重点函数proxy
            function proxy(target, sourceKey, key) { // target是vm,sourceKey是"_data",key是"age"
                sharedPropertyDefinition.get = function proxyGetter() {
                    return this["_data"]["age"];
                };
                sharedPropertyDefinition.set = function proxySetter(val) {
                    this["_data"]["age"] = val;
                };
                Object.defineProperty(vm, 'age', sharedPropertyDefinition);
            }
     -->
 
    <!-- 容器 -->
    <div id="app">
        <h1>姓名:{{name}}</h1>
        <h1>年龄:{{age}}岁</h1>
    </div>
 
    <!-- vue代码 -->
    <script>
 
        function isReserved(str) {
            var c = (str + '').charCodeAt(0);
            return c === 0x24 || c === 0x5f;
        }
 
        const vm = new Vue({
            el: '#app',
            data: {
                name: 'jackson',
                age: 35
            }
        })
 
        // 如果我们程序员不想走代理的方式读取data,想直接读取data当中的数据,可以通过_data和$data属性来访问。
        // 建议使用$data这个属性。
        console.log('name = ' + vm.$data.name)
        console.log('age = ' + vm.$data.age)
 
    </script>
</body>
 
</html>

1.2.7、data也可以是一个函数

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>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>data也可以是一个函数</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
    </div>
 
    <script>
        new Vue({
            el: "#app",
            data() {
                return {
                    msg: "zhangsan"
                };
            }
        });
 
        // 关于配置项:enumerable、configurable
        let phone = {
            name: "IphoneX"
        }
 
        Object.defineProperty(phone, "color", {
            value: "red",
            // true表示可以进行遍历:Object.keys(phone)
            enumerable: true,
            // true表示是可以被删除的:delete phone.color
            configurable: true
        });
    </script>
</body>
 
</html>

 1.2.8、事件绑定: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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的事件绑定</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        Vue事件处理:
            1.指令的语法格式:
                <标签 v-指令名:参数名="表达式">{{插值语法}}</标签>
                “表达式”位置都可以写什么?
                    常量、JS表达式、Vue实例所管理的XXX
            2. 在Vue当中完成事件绑定需要哪个指令呢?
                v-on指令。
                语法格式:
                    v-on:事件名="表达式"
                例如:
                    v-on:click="表达式" 表示当发生鼠标单击事件之后,执行表达式。
                    v-on:keydown="表达式" 表示当发生键盘按下事件之后,执行表达式。
            3. 在Vue当中,所有事件所关联的回调函数,需要在Vue实例的配置项methods中进行定义。
                methods是一个对象:{}
                在这个methods对象中可以定义多个回调函数。
            4. v-on指令也有简写形式
                v-on:click 简写为 @click
                v-on:keydown 简写为 @keydown
                v-on:mouseover 简写为 @mouseover
                ....
            5. 绑定的回调函数,如果函数调用时不需要传递任何参数,小括号()可以省略。
            6. Vue在调用回调函数的时候,会自动给回调函数传递一个对象,这个对象是:当前发生的事件对象。
            7. 在绑定回调函数的时候,可以在回调函数的参数上使用 $event 占位符,Vue框架看到这个 $event 占位符之后,会自动将当前事件以对象的形式传过去。
     -->
    <!-- 容器 -->
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 使用javascript原生代码如何完成事件绑定。 -->
        <button onclick="alert('hello')">hello</button>
 
        <!-- 使用Vue来完成事件绑定 -->
        <!-- 以下是错误的,因为alert()并没有被Vue实例管理。 -->
        <!-- <button v-on:click="alert('hello')">hello</button> -->
        <!-- 以下是错误的,因为sayHello()并没有被Vue实例管理。 -->
        <!-- <button v-on:click="sayHello()">hello</button> -->
 
        <!-- 正确的写法 -->
        <button v-on:click="sayHello()">hello</button>
 
        <!-- v-on指令的简写形式 -->
        <button @click="sayHi()">hi button</button>
        <button @click="sayHi($event, 'jack')">hi button2</button>
 
        <!-- 绑定的回调函数,如果不需要传任何参数,小括号() 可以省略 -->
        <button @click="sayWhat($event)">what button</button>
    </div>
    <!-- vue代码 -->
    <script>
        // 自定义一个函数
        // function sayHello(){
        //     alert('hello')
        // }
 
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Vue的事件绑定'
            },
            methods : {
                // 回调函数
                // sayHello : function(){
                //     alert('hello')
                // }
 
                // : function 可以省略
                sayHello(){
                    alert('hello2')
                },
 
                sayHi(event, name){
                    console.log(name, event)
                    //alert("hi " + name)
                },
 
                // 参数是事件对象
                sayWhat(event){
                    console.log(event)
                    console.log(event.target)
                    // 拿到按钮文本
                    console.log(event.target.innerText)
                }
            }
        })
    </script>
</body>
</html>

 1.2.9、关于事件回调中的this,计数器例子(this就是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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>关于事件回调函数中的this</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <!-- 容器 -->
    <div id="app">
        <h1>{{msg}}</h1>
        <h1>计数器:{{counter}}</h1>
        <button @click="counter++">点击我加1-第一种实现</button>
        <button @click="add()">点击我加1-第二种实现</button>
        <button @click="add2()">点击我加1-(箭头函数)</button>
    </div>
    <!-- vue代码 -->
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '关于事件回调函数中的this',
                counter: 0
            },
            // 1.methods对象中的方法可以通过vm去访问吗?可以。
            // 2.methods对象中的方法有没有做数据代理呢?没有。
            methods: {
                add() {
                    //counter++; // 错误的。
                    // 在这里需要操作counter变量?怎么办?
                    //console.log(vm === this) :true
                    this.counter++;
                },
                add2: () => {
                    //this.counter++;
                    //console.log(this === vm)
                    //箭头函数中没有this,箭头函数中的this是从父级作用域当中继承过来的。
                    //对于当前程序来说,父级作用域是全局作用域:window
                    console.log(this)
                },
                sayHi() {
                    alert('hi...')
                }
            }
        })
 
    </script>
</body>
 
</html>

 1.2.10、事件修饰符

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件修饰符</title>
    <!-- 安装Vue -->
    <script src="../js/vue.js"></script>
    <style>
        .divList{
            width: 300px;
            height: 200px;
            background-color: aquamarine;
            overflow: auto;
        }
        .item{
            width: 300px;
            height: 200px;
        }
    </style>
</head>
<body>
    <!--
        Vue当中提供的事件修饰符:
        .stop : 停止事件冒泡,等同于 event.stopPropagation()。
        .prevent : 等同于 event.preventDefault() 阻止事件的默认行为。
        .capture :添加事件监听器时使用事件捕获模式
                    添加事件监听器包括两种不同的方式:
                        一种是从内到外添加。(事件冒泡模式)
                        一种是从外到内添加。(事件捕获模式)
        .self :这个事件如果是“我自己元素”上发生的事件,这个事件不是别人给我传递过来的事件,则执行对应的程序。
        .once : 事件只发生一次
        .passive :passive翻译为顺从/不抵抗。无需等待,直接继续(立即)执行事件的默认行为。
                    .passive 和 .prevent 修饰符是对立的。不可以共存。(如果一起用,就会报错。)
                    .prevent:阻止事件的默认行为。
                    .passive:解除阻止。
     -->       
    <!-- 容器 -->
    <div id="app">
        <h1>{{msg}}</h1>
 
        <!-- 阻止事件的默认行为 -->
        <a href="https://www.baidu.com" @click.prevent="yi">百度</a> <br><br>
 
        <!-- 停止事件冒泡 -->
        <div @click="san">
            <div @click.stop="er">
                <button @click="yi">事件冒泡</button>
            </div>
        </div>
 
        <br><br>
 
        <!-- 添加事件监听器时使用事件捕获模式 -->
        <div @click.capture="san">
            <!-- 这里没有添加.capture修饰符,以下这个元素,以及这个元素的子元素,都会默认采用冒泡模式。 -->
            <div @click="er">
                <button @click="yi">添加事件监听器的时候采用事件捕获模式</button>
            </div>
        </div>
         
        <br>
        <br>
        <!-- .self修饰符 -->
        <div @click="san">
            <!-- 此处是button按钮向上冒泡传递古来的事件,所以不执行er -->
            <div @click.self="er">
                <button @click="yi">self修饰符</button>
            </div>
        </div>
 
        <br>
        <br>
        <!-- 在Vue当中,事件修饰符是可以多个联合使用的。
            但是需要注意:
                @click.self.stop:先.self,再.stop
                @click.stop.self:先.stop,再.self
         -->
        <div @click="san">
            <div @click="er">
                <button @click.self.stop="yi">self修饰符</button>
            </div>
        </div>
 
        <br>
        <br>
        <!-- .once修饰符:事件只发生一次 -->
        <button @click.once="yi">事件只发生一次</button>
 
        <!-- .passive修饰符 -->
        <div class="divList" @wheel.passive="testPassive">
            <div class="item">div1</div>
            <div class="item">div2</div>
            <div class="item">div3</div>
        </div>
 
    </div>
    <!-- vue代码 -->
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '事件修饰符'
            },
            methods : {
                yi(event){
                    //alert('去百度!!!!!!')
                    // 手动调用事件对象的preventDefault()方法,可以阻止事件的默认行为。
                    // 在Vue当中,这种事件的默认行为可以不采用手动调用DOM的方式来完成,可以使用事件修饰符:prevent。
                    //event.preventDefault();
                    alert(1)
                },
                er(){
                    alert(2)
                },
                san(){
                    alert(3)
                },
                testPassive(event){
                    for(let i = 0; i < 100000; i++){
                        console.log('test passive')
                    }
                    // 阻止事件的默认行为
                    //event.preventDefault()
                }
            }
        })
    </script>
</body>
</html>

1.2.11、按键修饰符

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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>按键修饰符</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        9个比较常用的按键修饰符:
            .enter
            .tab (必须配合keydown事件使用。)
            .delete (捕获“删除”和“退格”键)
            .esc
            .space
            .up
            .down
            .left
            .right
        怎么获取某个键的按键修饰符?
            第一步:通过event.key获取这个键的真实名字。
            第二步:将这个真实名字以kebab-case风格进行命名。
                PageDown是真实名字。经过命名之后:page-down
        按键修饰符是可以自定义的?
            通过Vue的全局配置对象config来进行按键修饰符的自定义。
            语法规则:
                Vue.config.keyCodes.按键修饰符的名字 = 键值
        系统修饰键:4个比较特殊的键
            ctrl、alt、shift、meta
            对于keydown事件来说:只要按下ctrl键,keydown事件就会触发。
            对于keyup事件来说:需要按下ctrl键,并且加上按下组合键,然后松开组合键之后,keyup事件才能触发。
     -->
    <div id="app">
        <h1>{{msg}}</h1>
        回车键:<input type="text" @keyup.enter="getInfo"><br>
        回车键(键值):<input type="text" @keyup.13="getInfo"><br>
        delete键:<input type="text" @keyup.delete="getInfo"><br>
        esc键:<input type="text" @keyup.esc="getInfo"><br>
        space键:<input type="text" @keyup.space="getInfo"><br>
        up键:<input type="text" @keyup.up="getInfo"><br>
        down键:<input type="text" @keyup.down="getInfo"><br>
        left键:<input type="text" @keyup.left="getInfo"><br>
        right键:<input type="text" @keyup.right="getInfo"><br>
        <!-- tab键无法触发keyup事件。只能触发keydown事件。 -->
        tab键: <input type="text" @keyup.tab="getInfo"><br>
        tab键(keydown): <input type="text" @keydown.tab="getInfo"><br>
        PageDown键: <input type="text" @keyup.page-down="getInfo"><br>
        huiche键: <input type="text" @keyup.huiche="getInfo"><br>
        ctrl键(keydown): <input type="text" @keydown.ctrl="getInfo"><br>
        ctrl键(keyup): <input type="text" @keyup.ctrl="getInfo"><br>
        ctrl键(keyup): <input type="text" @keyup.ctrl.i="getInfo"><br>
    </div>
 
    <script>
 
        // 自定义了一个按键修饰符:.huiche 。代表回车键。
        Vue.config.keyCodes.huiche = 13
 
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '按键修饰符'
            },
            methods : {
                getInfo(event){
                    // 当用户键入回车键的时候,获取用户输入的信息。
                    //if(event.keyCode === 13){
                        console.log(event.target.value)
                    //}
                    console.log(event.key)
                }
            }
        })
    </script>
</body>
</html>

1.2.12、计算属性-反转字符串案例(computed)

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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>计算属性-反转字符串</title>
    <script src="../js/vue.js"></script>
 
</head>
 
<body>
    <!--
        执行步骤:
            1、v-model绑定的数据发生变化
            2、插值语法中的方法会重新执行,执行methods中的方法
            3、方法中的this指向的是Vue实例,获取到最新的数据
            4、方法中的代码会重新执行,获取到最新的数据,然后返回
     -->
    <div id="app">
        <h1>{{message}}</h1><br>
        输入字符串:<input type="text" v-model="reversedMessageInfo"><br>
        <br>
        <!-- 在插值语法中可以调用方法,小括号不能省略。这个方法需要是Vue实例所管理的。 -->
        反转字符串-methods方式:{{reverseMessage_methods()}}<br>
        <br>
        反转字符串-compared方式:{{reverseMessage_computed}}<br>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue.js!',
                reversedMessageInfo: ''
 
                // 方法也可以直接放在data中,但是不推荐这样做
                // reverseMessage_methods(){
                //     return this.reversedMessageInfo.split('').reverse().join('');
                // }
            },
            methods: {
                // 反转字符串的方法
                reverseMessage_methods() {
                    return this.reversedMessageInfo.split('').reverse().join('');
                }
            },
            computed: {
                // 反转字符串的方法
                reverseMessage_computed() {
                    return this.reversedMessageInfo.split('').reverse().join('');
                }
            }
        })
    </script>
</body>
 
</html>

1.2.13、侦听属性-比较数字大小案例(watch)

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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>监听属性变化-数字大小比较案例</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        数字1:<input type="number" v-model="num1"><br>
        数字2:<input type="number" v-model="num2"><br>
        <hr>
        比较数值大小-watch方式: {{compareResult}}
        <br>
        <!-- 此处需要注意的是,computed中的是计算属性,不是方法,所以不需要加括号。 -->
        比较数值大小-computed方式: {{compareResult_computed}}
    </div>
 
    <script>
        new Vue({
            el: "#app",
            data: {
                msg: "监听属性变化-数值大小比较案例",
                num1: 0,
                num2: 0,
                compareResult: ''
            },
            computed: {
                compareResult_computed() {
                    let result = this.num1 - this.num2
                    if (result == 0) {
                        return this.num1 + ' = ' + this.num2
                    } else if (result > 0) {
                        return this.num1 + ' > ' + this.num2
                    } else {
                        return this.num1 + ' < ' + this.num2
                    }
                }
            },
            watch: {
                num1: {
                    // 设置immediate为true,可以在初始化的时候,调用一次handler方法。
                    immediate: true,
                    handler(val) {
                        let result = val - this.num2
                        if (result == 0) {
                            this.compareResult = val + ' = ' + this.num2
                        } else if (result > 0) {
                            this.compareResult = val + ' > ' + this.num2
                        } else {
                            this.compareResult = val + ' < ' + this.num2
                        }
                    }
                },
                num2: {
                    immediate: true,
                    handler(val) {
                        let result = this.num1 - val
                        if (result == 0) {
                            this.compareResult = this.num1 + ' = ' + val
                        } else if (result > 0) {
                            this.compareResult = this.num1 + ' > ' + val
                        } else {
                            this.compareResult = this.num1 + ' < ' + val
                        }
                    }
                }
            }
        });
    </script>
</body>
 
</html>

1.2.14、class样式绑定

分别有三种形式:字符串形式、数组形式、对象形式

字符串形式:适用场景(如果确定动态绑定的样式个数只有1个,但是名字不确定)

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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Class绑定之字符串形式</title>
    <script src="../js/vue.js"></script>
    <style>
        .static{
            border: 1px solid black;
            background-color: aquamarine;
        }
        .big{
            width: 200px;
            height: 200px;
        }
        .small{
            width: 100px;
            height: 100px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 静态写法 -->
        <div class="static small">{{msg}}</div>
        <br><br>
        <button @click="changeBig()">变大</button>
        <button @click="changeSmall()">变小</button>
        <!-- 动态写法:动静都有 -->
        <!-- 适用场景:如果确定动态绑定的样式个数只有1个,但是名字不确定。 -->
        <div class="static" :class="c1">{{msg}}</div>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Class绑定之字符串形式',
                c1 : 'small'
            },
            methods: {
                changeBig(){
                    this.c1 = 'big'
                },
                changeSmall(){
                    this.c1 = 'small'
                }
            },
        })
    </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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Class绑定之数组形式</title>
    <script src="../js/vue.js"></script>
    <style>
        .static {
            border: 1px solid black;
            width: 100px;
            height: 100px;
        }
 
        .active {
            background-color: green;
        }
 
        .text-danger {
            color: red;
        }
    </style>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 静态写法 -->
        <div class="static active text-danger">{{msg}}</div>
        <br>
        <!-- 动态写法:动静结合 -->
        <div class="static" :class="['active','text-danger']">{{msg}}</div>
        <br>
        <!-- 数组写法1 -->
        <div class="static" :class="[c1, c2]">{{msg}}</div>
        <br>
        <!-- 数组写法1 -->
        <!-- 适用场景:当样式的个数不确定,并且样式的名字也不确定的时候,可以采用数组形式。 -->
        <div class="static" :class="classArray">{{msg}}</div>
 
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msg: 'Class绑定之数组形式',
                c1: 'active',
                c2: 'text-danger',
                classArray: ['active', 'text-danger']
            }
        })
    </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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Class绑定之对象形式</title>
    <script src="../js/vue.js"></script>
    <style>
        .static {
            border: 1px solid black;
            width: 100px;
            height: 100px;
        }
        .active {
            background-color: green;
        }
        .text-danger {
            color: red;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 动态写法:动静结合 -->
        <!-- 对象形式的适用场景:样式的个数是固定的,样式的名字也是固定的,但是需要动态的决定样式用还是不用。 -->
        <div class="static" :class="classObj">{{msg}}</div>
        <br>
        <div class="static" :class="{active:true,'text-danger':false}">{{msg}}</div>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Class绑定之对象形式',
                classObj : {
                    // 该对象中属性的名字必须和样式名一致。
                    active : false,
                    'text-danger' : true
                }
            }
        })
    </script>
</body>
</html>

1.2.15、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
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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Style绑定</title>
    <script src="../js/vue.js"></script>
    <style>
        .static {
            border: 1px solid black;
            width: 100px;
            height: 100px;
        }
    </style>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 静态写法 -->
        <div class="static" style="background-color: green;">{{msg}}</div>
        <br>
        <!-- 动态写法:字符串形式 -->
        <div class="static" :style="myStyle">{{msg}}</div>
        <br>
        <!-- 动态写法:对象形式 -->
        <div class="static" :style="{backgroundColor: 'gray'}">{{msg}}</div>
        <br>
        <div class="static" :style="styleObj1">{{msg}}</div>
        <br>
        <!-- 动态写法:数组形式 -->
        <div class="static" :style="styleArray">{{msg}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msg: 'Style绑定',
                myStyle: 'background-color: gray;',
                styleObj1: {
                    backgroundColor: 'green'
                },
                styleArray: [
                    { backgroundColor: 'green' },
                    { color: 'red' }
                ]
            }
        })
    </script>
</body>
 
</html>

1.2.16、条件渲染v-if、v-else-if、v-else

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
79
80
81
82
83
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>条件渲染</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
 
        <h1>{{msg}}</h1>
        <!-- ------------------------------------------------------------------------------- -->
        <!--
            v-if指令的值:true/false
                true: 表示该元素会被渲染到页面上。
                false: 表示该元素不会被渲染到页面上。(注意:不是修改了CSS样式,是这个元素压根没有加载)
         -->
        <div v-if="false">{{msg}}</div>
        <div v-if="2 === 1">{{msg}}</div>
        <hr>
        <!-- ------------------------------------------------------------------------------- -->
 
        <!-- ------------------------------------------------------------------------------- -->
        <button @click="counter++">点我加1</button>
        <h3>{{counter}}</h3>
 
        <!-- 提醒:v-if和v-else之间不能断开。 -->
        <img :src="imgPath1" v-if="counter % 2 === 1">
        <img :src="imgPath2" v-else>
        <hr>
        <!-- ------------------------------------------------------------------------------- -->
        <!-- ------------------------------------------------------------------------------- -->
        温度:<input type="number" v-model="temprature"><br><br>
        <!-- 写法一:繁琐 -->
        天气:<span v-if="temprature <= 10">寒冷</span>
        <span v-if="temprature > 10 && temprature <= 25">凉爽</span>
        <span v-if="temprature > 25">炎热</span>
        <br>
        <!-- 写法一:简洁 -->
        天气:<span v-if="temprature <= 10">寒冷</span>
        <span v-else-if="temprature <= 25">凉爽</span>
        <span v-else>炎热</span>
        <br><br><br>
        <!-- ------------------------------------------------------------------------------- -->
        <!--
            v-show指令是通过修改元素的CSS样式的display属性来达到显示和隐藏的。
            v-if和v-show应该如何选择?
                1. 如果一个元素在页面上被频繁的隐藏和显示,建议使用v-show,因为此时使用v-if开销比较大。
                2. v-if的优点:页面加载速度快,提高了页面的渲染效率。
         -->
        <div v-show="false">你可以看到我吗?</div>
        <!-- ------------------------------------------------------------------------------- -->
 
        <!-- ------------------------------------------------------------------------------- -->
        <!-- template标签/元素只是起到占位的作用,不会真正的出现在页面上,也不会影响页面的结构。 -->
        <template v-if="counter === 10">
            <input type="text">
            <input type="checkbox">
            <input type="radio">
        </template>
        <!-- ------------------------------------------------------------------------------- -->
 
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '条件渲染',
                counter: 1,
                imgPath1: '../img/1.jpg',
                imgPath2: '../img/2.jpg',
                // 温度
                temprature: 0
            }
        })
    </script>
</body>
 
</html>

1.2.17、列表渲染: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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>列表渲染</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{msg}}</h1>
 
        <h2>遍历对象的属性</h2>
        <ul>
            <li v-for="(value, propertyName) of user">
                {{propertyName}},{{value}}
            </li>
        </ul>
 
        <h2>遍历字符串</h2>
        <ul>
            <li v-for="(c,index) of str">
                {{index}},{{c}}
            </li>
        </ul>
 
        <h2>遍历指定的次数</h2>
        <ul>
            <li v-for="(num,index) of counter">
                {{index}}, {{num}}
            </li>
        </ul>
 
 
        <h2>遍历数组</h2>
        <!-- 静态列表 -->
        <ul>
            <li>张三</li>
            <li>李四</li>
            <li>王五</li>
        </ul>
 
        <!-- 动态列表 -->
        <ul>
            <!--
                1. v-for要写在循环项上。
                2. v-for的语法规则:
                    v-for="(变量名,index) in/of 数组"
                    变量名 代表了 数组中的每一个元素
             -->
            <li v-for="fdsafds in names">
                {{fdsafds}}
            </li>
        </ul>
 
        <ul>
            <li v-for="name of names">
                {{name}}
            </li>
        </ul>
 
        <ul>
            <li v-for="(name,index) of names">
                {{name}}-{{index}}
            </li>
        </ul>
 
        <ul>
            <li v-for="(vip,index) of vips">
                会员名:{{vip.name}},年龄:{{vip.age}}岁
            </li>
        </ul>
 
        <table>
            <tr>
                <th>序号</th>
                <th>会员名</th>
                <th>年龄</th>
                <th>选择</th>
            </tr>
            <tr v-for="(vip,index) in vips">
                <td>{{index+1}}</td>
                <td>{{vip.name}}</td>
                <td>{{vip.age}}</td>
                <td><input type="checkbox"></td>
            </tr>
        </table>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '列表渲染',
                names : ['jack','lucy','james'],
                vips : [
                    {id:'111',name:'jack',age:20},
                    {id:'222',name:'lucy',age:30},
                    {id:'333',name:'james',age:40}
                ],
                user : {
                    id : '111',
                    name : '张三',
                    gender : '男'
                },
                str : '动力节点',
                counter : 10
            }
        })
    </script>
</body>
</html>

1.2.18、列表过滤(文本检索):computed、watch

computed

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">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>列表过滤</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <input type="text" v-model="keyword" placeholder="请输入想要查找的姓名,">
        <table>
            <tr>
                <th>编号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>地址</th>
            </tr>
            <tr v-for="user in filterUser" ::key="user.id">
                <td>{{user.id}}</td>
                <td>{{user.name}}</td>
                <td>{{user.age}}</td>
                <td>{{user.address}}</td>
            </tr>
        </table>
    </div>
 
    <script>
        new Vue({
            el: '#app',
            data: {
                keyword: '',
                msg: '列表过滤',
                users: [
                    { id: '100', name: '张三', age: '23', address: '北京丰台' },
                    { id: '200', name: '李四', age: '24', address: '北京朝阳' },
                    { id: '300', name: '王五', age: '25', address: '北京海淀' },
                    { id: '400', name: '赵六', age: '26', address: '北京昌平' },
                    { id: '500', name: '田七', age: '27', address: '北京大兴' },
                    { id: '600', name: '张小三', age: '28', address: '北京大兴' }
                ]
            },
            // 字符串搜索之computed计算属性实现
            computed: {
                filterUser() {
                    return this.users.filter((user) => {
                        return user.name.indexOf(this.keyword) >= 0
                    })
                }
            }
        });
    </script>
</body>
 
</html>

watch 

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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>列表过滤</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <input type="text" v-model="keyword" placeholder="请输入想要查找的姓名">
        <table>
            <tr>
                <th>编号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>地址</th>
            </tr>
            <tr v-for="user in filterUser" ::key="user.id">
                <td>{{user.id}}</td>
                <td>{{user.name}}</td>
                <td>{{user.age}}</td>
                <td>{{user.address}}</td>
            </tr>
        </table>
    </div>
 
    <script>
        new Vue({
            el: '#app',
            data: {
                keyword: '',
                msg: '列表过滤',
                users: [
                    { id: '100', name: '张三', age: '23', address: '北京丰台' },
                    { id: '200', name: '李四', age: '24', address: '北京朝阳' },
                    { id: '300', name: '王五', age: '25', address: '北京海淀' },
                    { id: '400', name: '赵六', age: '26', address: '北京昌平' },
                    { id: '500', name: '田七', age: '27', address: '北京大兴' },
                    { id: '600', name: '张小三', age: '28', address: '北京大兴' }
                ],
                filterUser:[]
            },
            // 字符串搜索之watch监听属性实现
            watch: {
                // 监听keyword的变化
                keyword: {
                    immediate: true,
                    handler(val) {
                        this.filterUser = this.users.filter((user) => {
                            return user.name.indexOf(val) >= 0
                        })
                    }
                }
            }
        });
    </script>
</body>
 
</html>

1.2.19、表单数据收集

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
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表单数据的收集</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <!-- 阻止表单的默认提交行为,第一种:@submit.prevent  -->
        <form @submit.prevent="send">
            用户名:<input type="text" v-model.trim="user.username"><br><br>
            密码:<input type="password" v-model="user.password"><br><br>
            年龄:<input type="number" v-model.number="user.age"><br><br>
            性别:
            男<input type="radio" name="gender" value="1" v-model="user.gender">
            女<input type="radio" name="gender" value="0" v-model="user.gender"><br><br>
            爱好:
            <!-- 注意:对于checkbox来说,如果没有手动指定value,那么会拿这个标签的checked属性的值作为value -->
            旅游<input type="checkbox" v-model="user.interest" value="travel">
            运动<input type="checkbox" v-model="user.interest" value="sport">
            唱歌<input type="checkbox" v-model="user.interest" value="sing"><br><br>
            学历:
            <select v-model="user.grade">
                <option value="">请选择学历</option>
                <option value="zk">专科</option>
                <option value="bk">本科</option>
                <option value="ss">硕士</option>
            </select><br><br>
            简介:
            <!--  -->
            <textarea cols="50" rows="15" v-model.lazy="user.introduce"></textarea><br><br>
            <input type="checkbox" v-model="user.accept">阅读并接受协议<br><br>
 
        <!-- 阻止表单的默认提交行为,第二种:@click.prevent  -->
            <!-- <button @click.prevent="send">注册</button> -->
            <button>注册</button>
        </form>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                user: {
                    username: '',
                    password: '',
                    age: '',
                    gender: '1',
                    interest: ['travel'],
                    grade: '',
                    introduce: '',
                    accept: ''
                },
                msg: '表单数据的收集'
            },
            methods: {
                send() {
                    // 将数据收集好,发送给服务器。
                    console.log(JSON.stringify(this.$data))
                    console.log(JSON.stringify(this.user))
                }
            }
        })
    </script>
</body>
 
</html>

1.2.20、过滤器(在Vue3被弃用)

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>过滤器</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        需求:
            从服务器端返回了一个商品的价格price,这个price的值可能是这几种情况:''null、undefined、60.5
            要求:
                如果是''null、undefined ,页面上统一显示为 -
                如果不是 ''null、undefined,则页面上显示真实的数字即可。
        在Vue3当中,已经将过滤器语法废弃了。
     -->
    <div id="app">
        <h1>{{msg}}</h1>
        <h2>商品价格:{{formatPrice}}</h2>
        <h2>商品价格:{{formatPrice2()}}</h2>
        <h2>商品价格:{{price | filterA | filterB(3)}}</h2>
        <input type="text" :value="price | filterA | filterB(3)">
    </div>
 
    <hr>
 
    <div id="app2">
        <h2>商品价格:{{price | filterA | filterB(3)}}</h2>
    </div>
 
    <script>
 
        // 配置全局的过滤器。
        Vue.filter('filterA', function(val){
            if(val === null || val === undefined || val === ''){
                return '-'
            }
            return val
        })
 
        Vue.filter('filterB', function(val, number){
            return val.toFixed(number)
        })
 
        const vm2 = new Vue({
            el : '#app2',
            data : {
                price : 20.3
            }
        })
 
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '过滤器',
                price : 50.6
            },
            methods: {
                formatPrice2(){
                    if(this.price === '' || this.price === undefined || this.price === null){
                        return '-'
                    }
                    return this.price
                }
            },
            computed : {
                formatPrice(){
                    if(this.price === '' || this.price === undefined || this.price === null){
                        return '-'
                    }
                    return this.price
                }
            },
            /* filters : {
                // 局部过滤器
                filterA(val){
                    if(val === null || val === undefined || val === ''){
                        return '-'
                    }
                    return val
                },
                filterB(val, number){
                    // 确保传递过来的数据val,保留两位小数。
                    return val.toFixed(number)
                }
            } */
        })
    </script>
</body>
</html>

1.2.21、Vue的其他指令(v-text、v-html、v-once)

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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的其它指令</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{msg}},test</h1>
        <!--
            v-text指令:
                可以将指令的内容拿出来填充到标签体当中。和JS的innerText一样。
                这种填充是以覆盖的形式进行的。先清空标签体当中原有的内容,填充新的内容。
                即使内容是一段HTML代码,这种方式也不会将HTML代码解析并执行。只会当做普通
                文本来处理。
         -->
        <h1 v-text="msg">test</h1>
        <h1 v-text="name">test</h1>
        <h1 v-text="s1"></h1>
 
        <!--
            v-html指令:
                和v-text一样,也是填充标签体内容。也是采用覆盖的形式进行。
                只不过v-html会将内容当做一段HTML代码解析并执行。
         -->
         <h1 v-html="s1"></h1>
         <br><br>
         使用了v-once指令,那么这个元素只会渲染一次。
         <ul>
            <li v-for="user,index of users" :key="index" v-once>
                {{user}}
            </li>
        </ul>
 
        <ul>
            <li v-for="user,index of users" :key="index">
                {{user}}
            </li>
        </ul>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Vue的其它指令',
                name : 'jack',
                s1 : '<h1>欢迎大家学习Vue!</h1>',
                users : ['jack', 'lucy', 'james']
            }
        })
    </script>
</body>
</html>

1.2.22、自定义指令(directives)

例:

  • text-danger:将属性值设置为红色
  • bind-blue:设置属性的父级元素背景色

关于自定义指令的区别:

  • 函数式:功能简洁
  • 对象式:功能更加细粒化
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义指令</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
 
    <div id="app">
        <h1>自定义指令</h1>
        <div v-text="msg"></div>
        <div v-text-danger="msg"></div>
        用户名:<input type="text" v-bind:value="username">
        <!--
            需要一个指令,可以和v-bind指令完成相同的功能,同时将该元素的父级元素的背景色设置为蓝色。
         -->
        <div>
            用户名:<input type="text" v-bind-blue="username">
        </div>
    </div>
    <hr>
    <hr>
    <div id="app2">
        <div v-text-danger="msg"></div>
        <div>
            用户名:<input type="text" v-bind-blue="username">
        </div>
    </div>
 
    <script>
        // 定义全局的指令
        // 函数式
        Vue.directive('text-danger', function (element, binding) {
            //对于自定义指令来说,函数体当中的this是window,而不是vue实例。
            console.log(this)
            element.innerText = binding.value
            element.style.color = 'red'
        })
 
        // 对象式
        Vue.directive('bind-blue', {
            // 元素与指令初次绑定的时候,自动调用bind
            bind(element, binding) {
                element.value = binding.value
                console.log(this)
            },
            // 元素被插入到页面之后,这个函数自动被调用。
            inserted(element, binding) {
                element.parentNode.style.backgroundColor = 'skyblue'
                console.log(this)
            },
            // 当模板重新解析的时候,这个函数会被自动调用。
            update(element, binding) {
                element.value = binding.value
                console.log(this)
            }
        })
 
        const vm2 = new Vue({
            el: '#app2',
            data: {
                msg: '欢迎学习Vue框架!',
                username: 'lucy'
            }
        })
 
        const vm = new Vue({
            el: '#app',
            data: {
                msg: '自定义指令',
                username: 'jackson'
            },
            directives: {
                // 指令1
                // 指令2
                // ...
                // 关于指令的名字:1. v- 不需要写。 2. Vue官方建议指令的名字要全部小写。如果是多个单词的话,请使用 - 进行衔接。
                // 这个回调函数的执行时机包括两个:第一个:标签和指令第一次绑定的时候。第二个:模板被重新解析的时候。
                // 这个回调函数有两个参数:第一个参数是真实的dom元素。 第二个参数是标签与指令之间绑定关系的对象。
                // 这种方式属于函数式方式。
                /* 'text-danger' : function(element, binding){
                    console.log('@')
                    element.innerText = binding.value
                    element.style.color = 'red'
                }, */
                /* 'bind-blue' : function(element, binding){
                    element.value = binding.value
                    console.log(element)
                    // 为什么是null,原因是这个函数在执行的时候,指令和元素完成了绑定,但是只是在内存当中完成了绑定,元素还没有被插入到页面当中。
                    console.log(element.parentNode)
                    element.parentNode.style.backgroundColor = 'blue'
                } */
 
 
                // 对象式
                /* 'bind-blue' : {
                    // 这个对象中三个方法的名字不能随便写。
                    // 这三个函数将来都会被自动调用。
                    // 元素与指令初次绑定的时候,自动调用bind
                    // 注意:在特定的时间节点调用特定的函数,这种被调用的函数称为钩子函数。
                    bind(element, binding){
                        element.value = binding.value
                    },
                    // 元素被插入到页面之后,这个函数自动被调用。
                    inserted(element, binding){
                        element.parentNode.style.backgroundColor = 'blue'
                    },
                    // 当模板重新解析的时候,这个函数会被自动调用。
                    update(element, binding){
                        element.value = binding.value
                    }
                } */
            }
        })
    </script>
</body>
 
</html>

 1.2.23、响应式与数据劫持

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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>响应式与数据劫持</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <div>姓名:{{name}}</div>
        <div>年龄:{{age}}岁</div>
        <div>数字:{{a.b.c.e}}</div>
        <div>邮箱:{{a.email}}</div>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '响应式与数据劫持',
                name : 'jackson',
                age : 20,
                a : {
                    b : {
                        c : {
                            e : 1
                        }
                    }
                }
            }
        })
 
        // 测试:后期给Vue实例动态的追加的一些属性,会添加响应式处理吗?
        // 目前来看,通过这种方式后期给vm追加的属性并没有添加响应式处理。
        //vm.$data.a.email = 'jack@126.com'
 
        // 如果你想给后期追加的属性添加响应式处理的话,调用以下两个方法都可以:
        // Vue.set() 、 vm.$set()
        //Vue.set(目标对象, 属性名, 属性值)
        //Vue.set(vm.$data.a, 'email', 'jack@126.com')
        //Vue.set(vm.a, 'email', 'jack@123.com')
        vm.$set(vm.a, 'email', 'jack@456.com')
 
        // 避免在运行时向Vue实例或其根$data添加响应式
        // 不能直接给vm / vm.$data 追加响应式属性。只能在声明时提前定义好。
        //Vue.set(vm, 'x', '1')
        //Vue.set(vm.$data, 'x', '1')
 
    </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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数组的响应式处理</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!--
        1. 通过数组的下标去修改数组中的元素,默认情况下是没有添加响应式处理的。怎么解决?
         
        2. 第一种方案:
            vm.$set(数组对象, 下标, 值)
            Vue.set(数组对象, 下标, 值)
 
        3. 第二种方案:
            push():在数组的末尾添加一个或多个元素,并返回新的长度。
                vm.users.push('jackson')
            pop():删除数组的最后一个元素,并返回该元素。
                vm.users.pop()
            reverse():颠倒数组中元素的顺序。
                vm.users.reverse()
            splice():从数组中替换元素。
                vm.users.splice(下标, 替换的数量, 替换的元素),
                vm.users.splice(1, 1, 'jackson')
            shift():删除数组的第一个元素,并返回该元素。
                vm.users.shift()
            unshift():在数组的开头添加一个或多个元素,并返回新的长度。
                vm.users.unshift('jackson')
            sort():对数组的元素进行排序,按照字母或数字的顺序。
                vm.users.sort()
            在Vue当中,通过以上的7个方法来给数组添加响应式处理。
     -->
    <div id="app">
        <h1>{{msg}}</h1>
        <ul>
            <li v-for="user in users">
                {{user}}
            </li>
        </ul>
        <ul>
            <li v-for="vip in vips" :key="vip.id">
                {{vip.name}}
            </li>
        </ul>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : '数组的响应式处理',
                users : ['jack', 'lucy', 'james'],
                vips : [
                    {id:'111', name:'zhangsan'},
                    {id:'222', name:'lisi'}
                ]
            }
        })
    </script>
</body>
</html> 

1.2.24、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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的生命周期</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <div id="app">
        <h1>{{msg}}</h1>
        <h3>计数器:{{counter}}</h3>
        <h3 v-text="counter"></h3>
        <button @click="add()">点我加1</button>
        <button @click="destroy()">点我销毁</button>
    </div>
    <script>
        const vm = new Vue({
            el : '#app',
            data : {
                msg : 'Vue生命周期',
                counter : 1
            },
            methods: {
                add(){
                    console.log('add....')
                    this.counter++
                },
                destroy(){
                    // 销毁vm
                    this.$destroy()
                },
                /* m(){
                    console.log('m....')
                } */
            },
            watch : {
                counter(){
                    console.log('counter被监视一次!')
                }
            },
            /*
            1.初始阶段
                el有,template也有,最终编译template模板语句。
                el有,template没有,最终编译el模板语句。
                el没有的时候,需要手动调用 vm.$mount(el) 进行手动挂载,然后流程才能继续。此时如果template有,最终编译template模板语句。
                el没有的时候,需要手动调用 vm.$mount(el) 进行手动挂载,然后流程才能继续。此时如果没有template,最终编译el模板语句。
 
                结论:
                    流程要想继续:el必须存在。
                    el和template同时存在,优先选择template。如果没有template,才会选择el。
            */
            beforeCreate() {
                // 创建前
                // 创建前指的是:数据代理和数据监测的创建前。
                // 此时还无法访问data当中的数据。包括methods也是无法访问的。
                console.log('beforeCreate', this.counter)
                // 调用methods报错了,不存在。
                //this.m()
            },
            created() {
                // 创建后
                // 创建后表示数据代理和数据监测创建完毕,可以访问data中的数据了。
                console.log('created', this.counter)
                // 可以访问methods了。
                //this.m()
            },
            // 2.挂载阶段
            beforeMount() {
                // 挂载前
                console.log('beforeMount')
            },
            mounted() {
                // 挂载后
                console.log('mounted')
                console.log(this.$el)
                console.log(this.$el instanceof HTMLElement)
            },
            // 3.更新阶段
            beforeUpdate() {
                // 更新前
                console.log('beforeUpdate')
            },
            updated() {
                // 更新后
                console.log('updated')
            },
            // 4.销毁阶段
            beforeDestroy() {
                // 销毁前
                console.log('beforeDestroy')
                console.log(this)
                this.counter = 1000
            },
            destroyed() {
                // 销毁后
                console.log('destroyed')
                console.log(this)
            },
        })
    </script>
</body>
</html>

1.3、Vue组件化开发

1.3.1、第一个组件程序

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第一个组件程序</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="app">
        <h1>{{msg}}</h1>
 
        <!-- 3、使用组件 -->
        <my-component></my-component>
        <userlist></userlist>
        <userlogin></userlogin>
    </div>
 
    <hr>
    <div id="app2">
        <userlogin></userlogin>
    </div>
 
    <script>
        // ##########################1、创建组件###########################################
        /* let myComponent = Vue.extend(
            {
                template: `
                    <ul>
                        <li v-for="user,index in users" :key="user.id">
                            {{user.id}}--{{user.name}}--{{user.age}}
                        </li>
                    </ul>
                `,
                data() {
                    return {
                        users: [
                            { id: '001', name: '张三', age: 18 },
                            { id: '002', name: '李四', age: 19 },
                            { id: '003', name: '王五', age: 20 },
                        ]
                    }
                }
            }
        ); */
        // 创建组件简写
        let myComponent = {
            template: `
                <ul>
                    <li v-for="user,index in users" :key="user.id">
                        {{user.id}}--{{user.name}}--{{user.age}}
                    </li>
                </ul>
            `,
            data() {
                return {
                    users: [
                        { id: '001', name: '张三', age: 18 },
                        { id: '002', name: '李四', age: 19 },
                        { id: '003', name: '王五', age: 20 },
                    ]
                }
            }
        }
         
        let myUserLogin = Vue.extend({
            template: `
                <div>
                    <h1>用户登录</h1>
                    <form @submit.prevent="login">
                        用户名:<input type="text" v-model="username"> <br>
                        密码:<input type="password" v-model="password" autocomplete><br>
                        <input type="submit" value="登录">
                    </form>
                </div>
            `,
            data() {
                return {
                    username: '',
                    password: ''
                }
            },
            methods: {
                // 阻止表单默认提交
                login() {
                    alert(this.username + "," + this.password)
                }
            }
 
        });
        // ##########################创建组件###########################################
 
        // 2、注册组件(全局),写在组件创建之后
        Vue.component('userlogin', myUserLogin)
 
        // ##########################创建Vue实例###########################################
        let myVue = new Vue({
            el: '#app',
            data: {
                msg: '第一个组件程序',
                users: [
                    { id: '001', name: '张三', age: 18 },
                    { id: '002', name: '李四', age: 19 },
                    { id: '003', name: '王五', age: 20 },
                ]
            },
            // 2、注册组件(局部)
            components: {
                myComponent,
                // 起别名
                userlist: myComponent
            }
        })
 
        // 创建Vue实例
        let myVue2 = new Vue({
            el: '#app2'
        })
        // ##########################创建Vue实例###########################################
    </script>
</body>
 
</html>

1.3.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
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
79
80
81
82
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件的嵌套</title>
    <script src="../js/vue.js"></script>
</head>
 
<body>
    <div id="root">
        <!-- 3、使用组件 -->
        <app></app>
    </div>
    <script>
 
 
        let x1 = {
            template: `
                <div>
                    <h1>x1组件</h1>
                </div>
            `
        }
        let x = {
            template: `
                <div>
                    <h1>x组件</h1>
                    <!--使用组件-->
                    <x1></x1>
                </div>
            `,
            components: {
                x1
            }
        }
        let y1 = {
            template: `
                <div>
                    <h1>y1组件</h1>
                </div>
            `
        }
        let y = {
            template: `
                <div>
                    <h1>y组件</h1>
                    <!--使用组件-->
                    <y1></y1>
                </div>
            `,
            components: {
                y1
            }
        }
 
        // 1、创建组件
        let app = {
            template: `
                <div>
                    <h1>app组件</h1>
                    <!--使用组件-->
                    <x></x>
                    <y></y>
                </div>
            `,
            components: {
                x, y
            }
        };
        new Vue({
            el: '#root',
            // 2、注册组件
            components: {
                app
            }
        });
    </script>
</body>
 
</html>

 1.4、Vue脚手架

1.4.1、NodeJs安装

https://www.cnblogs.com/zhangzhixi/p/17642325.html

1.4.2、Vue脚手架安装

Vue的脚手架(Vue CLI: Command Line Interface)是Vue官方提供的标准化开发平台。

它可以将我们.vue的代码进行编译生成html css js代码,并且可以将这些代码自动发布到它自带的服务器上,为我们Vue的开发提供了一条龙服务。

脚手架官网地址:https://cli.vuejs.org/zh

安装脚手架

1
npm install -g @vue/cli

创建项目(自带HelloWorld案例)

1
vue create vue_pro

这里选择Vue2,

  • babel:负责ES6语法转换成ES5。
  • eslint:负责语法检查的。

回车之后,就开始创建项目,创建脚手架环境(内置了webpack loader),自动生成HelloWorld案例。

编译Vue程序  

1
2
cd vue_pro
npm run serve

访问程序:

 

 1.4.3、脚手架目录结构

  • package.json:包的说明书(包的名字,包的版本,依赖哪些库)。该文件里有webpack的短命令:
    • serve(启动内置服务器)
    • build命令是最后一次的编译,生成html css js,给后端人员
    • lint做语法检查的。

 1.4.4、分析脚手架HelloWorld程序

 

可以看到在index.html中只有一个容器。没有引入vue.js,也没有引入main.js

Vue脚手架可以自动找到main.js文件。(所以main.js文件名不要修改,位置也不要随便移动)

 

接下来就是将之前写的程序拷贝到脚手架中,进行测试。

需要拷贝过来的是:App.vue、X.vue、Y.vue、X1.vue、Y1.vue。

main.js和index.html都不需要了,因为脚手架中有。

 

只需要将App.vue中的路径修改一下即可:

 

打开VSCode终端:ctrl + `

在终端中执行:npm run serve

报错了:

 

导致这个错误的原因是:组件的名字应该由多单词组成。这是eslint进行的es语法检测。

解决这个问题有两种方案:

第一种:把所有组件的名字修改一下。

第二种:在vue.config.js文件中进行脚手架的默认配置。配置如下:

 

在终端中ctrl + c 两次,终止之前的服务,再次运行命令:npm run serve

 

 1.4.5、props配置项

使用props配置可以接收其他组件传过来的数据,让组件的数据变为动态数据,三种接收方式:

(1)     简单接收

1
props : [‘name’,’age’,’sex’]

(2)     接收时添加类型限制

1
2
3
4
5
props: {
    name: String,
    age: Number,
    sex: String
}

(3)     接收时添加类型限制,必要性限制,默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
props : {
    name : {
        type : Number,
        required : true
    },
    age : {
        type : Number,
        default : 10
    },
    sex : {
        type : String,
        default : '男'
    }
}

 

 在上面的案例中,通常我们给属性赋值是通过在data中给属性赋值,如下所示:

 可以看到上面的程序是有问题,如果我们想要数据是动态的话,这时候需要一个个修改其属性值,比较繁琐麻烦。

有没有可以在标签使用时动态给属性传参呢?这时候就可以通过props配置项:

car.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
<template>
    <div>
        <h3>品牌:{{brand}}</h3>
        <h3>价格:{{price}}</h3>
        <h3>颜色:{{color}}</h3>
    </div>
</template>
 
<script>
export default {
    /* data() {
        return {
            brand: '奔驰',
            price: 1000000,
            color: '黑色'
        }
    } */
    // props接收父组件传递过来的数据
    props: ['brand', 'price', 'color']
}
</script>
 
<style>
 
</style>

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
  <div>
    <h1>我是App组件</h1>
    <!-- 传递属性值 -->
    <car brand="奔驰" :price="100000" color="黑色"></car>
    <hr />
    <car brand="宝马" :price="200000" color="白色"></car>
    <hr />
    <car brand="奥迪" :price="300000" color="红色"></car>
  </div>
</template>
 
<script>
import car from "./components/car.vue";
export default {
  components: {
    car,
  },
};
</script>
 
<style>
</style>

 1.4.6、在父组件中获取子组件信息:ref

比如上个例子,App.vue可以看做父组件、car.vue看作是子组件,想在父组件中获取子组件中的属性值等信息,就可以使用到标签体中的ref属性。

1、打标记

1
<car ref="benzCar" brand="奔驰" :price="100000" color="黑色"></car>

2、获取值

1
2
3
4
5
6
// 获取子组件
 console.log(this.$refs.benzCar);
// 获取子组件的属性
console.log(this.$refs.benzCar.brand);
 // 获取dom元素
console.log(this.$refs.h1Msg.innerText);

App.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
39
40
41
42
43
44
<template>
  <div>
    <h1 ref="h1Msg">{{ msg }}</h1>
    <!-- 传递属性值 -->
    <car ref="benzCar" brand="奔驰" :price="100000" color="黑色"></car>
    <hr />
    <car ref="bmwCar" brand="宝马" :price="200000" color="白色"></car>
    <hr />
    <car brand="奥迪" :price="300000" color="红色"></car>
    <button @click="printCarInfo()" value="点我获取汽车属性">
      点我获取汽车属性
    </button>
  </div>
</template>
 
<script>
import car from "./components/car.vue";
export default {
  data() {
    return {
      msg: "我是App组件",
    };
  },
  components: {
    car,
  },
  methods: {
    printCarInfo() {
      // 获取子组件
      console.log(this.$refs.benzCar);
      console.log(this.$refs.bmwCar);
      // 获取子组件的属性
      console.log(this.$refs.benzCar.brand);
      console.log(this.$refs.bmwCar.brand);
 
      // 获取dom元素
      console.log(this.$refs.h1Msg.innerText);
    },
  },
};
</script>
 
<style>
</style>

 1.4.7、mixins配置(混入)(代码复用)

如图所示,其中两段方法是一样的,是否可以进行优化,将代码复用呢?

 运行效果:

可以看到以上vip.vue和user.vue代码中都有相同的methods,这个代码可以复用吗?可以使用mixins配置进行混入。实现步骤:

第一步:创建混入

单独定义一个mixin.js(一般和main.js在同级目录),代码如下:

1
2
3
4
5
6
7
8
// 1、定义一个混入对象
export const mix1 = {
    methods: {
        printInfo() {
            console.log(this.name, this.age);
        }
    }
}

2、引入和使用混入

全局混入:

1.4.8、局部样式(scoped)

如下所示定义了两个相同名称的class,并分别设置背景颜色为红色和蓝色

这时候在页面上面显示的是红色的背景色,原因是因为在App.vue中先引入了user.vue,如果先引入vip.vue,那么背景色就会都变为蓝色。

 如何解决呢?想要每个组件拥有自己的样式:只需要在style中添加scoped标签即可

Vue-高级部分

2.1、Vue与Ajax

2.1.1、回顾发送AJax异步请求的方式

发送AJAX异步请求的常见方式包括:

1. 原生方式,使用浏览器内置的JS对象XMLHttpRequest

1
2
3
4
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){}
xhr.open()
xhr.send()

2. 原生方式,使用浏览器内置的JS函数fetch

1
fetch(‘url’, {method : ‘GET’}).then().then()

3. 第三方库方式,JS库jQuery(对XMLHttpRequest进行的封装)

1
2
$.get()
$.post()

4. 第三方库方式,基于Promise的HTTP库:axios (对XMLHttpRequest进行的封装),axios是Vue官方推荐使用的。

1
2
3
4
5
6
7
8
axios.get('').then(
    response => {
        console.log('服务器响应回来的数据:', response.data)
    },
    error => {
        console.log('错误信息:', error.message)
    }
)

2.1.2、回顾AJax跨域

1.什么是跨域访问

1
2
3
4
5
6
7
8
9
10
11
12
(1) 在a页面中想获取b页面中的资源,如果a页面和b页面所处的协议、域名、端口不同(只要有一个不同),所进行的访问行动都是跨域的。
(2) 哪些跨域行为是允许的?
    ①   直接在浏览器地址栏上输入地址进行访问
    ②   超链接
    ③   <img src=”其它网站的图片是允许的”>
    ④   <link href=”其它网站的css文件是允许的”>
    ⑤   <script src=”其它网站的js文件是允许的”>
    ⑥   ......
(3) 哪些跨域行为是不允许的?
    ①   AJAX请求是不允许的
    ②   Cookie、localStorage、IndexedDB等存储性内容是不允许的
    ③   DOM节点是不允许的

2.AJax无法跨域的原因:同源策略

1
2
3
4
5
(1)
    同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。
    同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
(2)
    AJAX请求不允许跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

3.解决AJax跨域的方案包括哪些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(1) CORS方案(工作中常用的)
    这种方案主要是后端的一种解决方案,被访问的资源设置响应头,告诉浏览器我这个资源是允许跨域访问的:
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
(2) jsonp方案(面试常问的)
    采用的是<script src=””>不受同源策略的限制来实现的,但只能解决GET请求。
(3) 代理服务器方案(工作中常用的)
    Nginx反向代理
    Node中间件代理
    vue-cli(Vue脚手架自带的8080服务器也可以作为代理服务器,需要通过配置vue.config.js来启用这个代理)
(4) postMesssage
(5) websocket
(6) window.name + iframe
(7) location.hash + iframe
(8) document.domain + iframe
(9) ......

2.1.3、演示跨域

Vue脚手架内置服务器的地址:http://localhost:8080

SpringBoot1项目-User地址:http://localhost:8000/getUserList

复制代码
package com.zhixi.controller;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangzhixi
 * @version 1.0
 * @description
 * @date 2023-09-01 9:10
 */
@RestController
public class UserController {

    @GetMapping("/getUserList")
    public List<User> getUserList(){
        List<User> userList = new ArrayList<>();
        userList.add(new User("张三", 23, "河南信阳"));
        userList.add(new User("李四", 24, "河南南阳"));
        userList.add(new User("王五", 25, "河南濮阳"));
        return userList;

    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class User{
    private String name;
    private Integer age;
    private String address;
}
UserController
复制代码

SpringBoot2项目-Vip地址:http://localhost:8001/getVipList

复制代码
package com.zhixi.controler;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangzhixi
 * @version 1.0
 * @description
 * @date 2023-09-01 9:17
 */
@RestController
public class VipController {
    @GetMapping("/getVipList")
    public List<Vip> getVipList() {
        List<Vip> vipList = new ArrayList<>();
        vipList.add(new Vip("马云", 58, "浙江杭州"));
        vipList.add(new Vip("刘强东", 49, "江苏宿迁"));
        vipList.add(new Vip("雷军", 53, "湖北仙桃"));
        return vipList;
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Vip {
    private String name;
    private Integer age;
    private String address;
}
VipController
复制代码


 1.安装axios库

1
npm i axios

2.引入axios库

3.发送ajax请求  

1
2
3
4
5
6
7
8
9
10
11
12
import axios from "axios";
 
mounted() {
    // 发送ajax请求
    axios.get("http://localhost:8000/getUserList").then(
      (response) => {
        console.log(response.data);
      },
      (error) => {
        console.log(error.message);
      }
);

以上的访问表示:在8080服务器(Vue)中发送AJAX请求访问8000服务器,必然会出现AJAX跨域问题:

2.1.4、解决跨域

在Vue中解决跨域的方法是:启用Vue脚手架内置服务器8080的代理功能。

简单开启:

vue.config.js文件中添加如下配置:

1
2
3
4
5
devServer: {
  // 后端服务器:协议、IP、端口
  // 含义:Vue脚手架内置的8080服务器负责代理访问8000服务器
  proxy: 'http://localhost:8000'
}

发送ajax时,地址需要修改为如下:

刷新页面,可以看到成功打印出来了user信息:


 如何验证会先走vue项目8080的请求呢?在public下新建一个文件,文件名为getUserList,写入内容随意,然后再次刷新,可以看到走的是vue服务器8080的请求了:

高级开启(常用)

vue.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
devServer: {
  proxy: {
    // 后端服务,访问前缀
    '/api': {
      // 后端服务,协议、IP、端口
      target: 'http://localhost:8000',
      pathRewrite: { '^/api': '' }, // 重写路径,正则表达式去除前缀,因为后端服务器是没有/api访问前缀的
      ws: true, // 支持websocket
      changeOrigin: true // true表示改变起源(让目标服务器不知道真正的起源)
    },
    '/abc': {
      target: 'http://localhost:8001',
      pathRewrite: { '^/abc': '' },
      ws: true, // 默认值true
      changeOrigin: true // 默认值true
    }
  }
}

页面:新建按钮,分别访问8000和8001服务器资源:

1
2
3
<button @click="getUserList()">获取普通用户列表信息</button>
<br />
<button @click="getVipList()">获取Vip用户列表信息</button>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
methods: {
  getUserList() {
    // 当前按钮这个页面就是在8080服务器上,又去访问8080服务器上的资源,所以http://localhost:8080可以省略。
    axios.get("/api/getUserList").then(
      (response) => {
        console.log("服务器响应回来的数据:", response.data);
      },
      (error) => {
        console.log("错误信息:", error.message);
      }
    );
  },
  getVipList() {
    axios.get("/abc/getVipList").then(
      (response) => {
        console.log("服务器响应回来的数据:", response.data);
      },
      (error) => {
        console.log("错误信息:", error.message);
      }
    );
  }
}

访问到资源,成功解决跨域问题:

2.2、实现城市搜索展示天气预报功能

 代码地址:https://gitee.com/zhang-zhixi/vue-demo-bjpowernode/tree/master/%E9%AB%98%E7%BA%A7%E9%83%A8%E5%88%86/vue_pro/16-Weather-%E5%A4%A9%E6%B0%94%E9%A2%84%E6%8A%A5%E6%A1%88%E4%BE%8B

效果:

 2.3、vuex

2.3.1、vuex概述

1. vuex是实现数据集中式状态管理的插件。数据由vuex统一管理。其它组件都去使用vuex中的数据。只要有其中一个组件去修改了这个共享的数据,其它组件会同步更新。

一定要注意:全局事件总线和vuex插件的区别:

  • (1)     全局事件总线关注点:组件和组件之间数据如何传递,一个绑定$on,一个触发$emit。数据实际上还是在局部的组件当中,并没有真正的让数据共享。只是数据传来传去。
  • (2)     vuex插件的关注点:共享数据本身就在vuex上。其中任何一个组件去操作这个数据,其它组件都会同步更新。是真正意义的数据共享。

  • (3)     使用vuex的场景是:多个组件之间依赖于同一状态。来自不同组件的行为需要变更同一状态。

 

2.3.2、vuex环境搭建

1. 安装vuex

1
2
3
# 因为Vue和vuex版本没有对应上,这里是需要注意的
vue2安装vuex3版本:npm i vuex@3
vue3安装vuex4版本:npm i vuex@4

2. 创建目录和js文件(目录和文件名不是必须叫这个)

(1)     目录:vuex

(2)     js文件:store.js

vuex/store.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
// 引入Vue,因为下面使用Vuex插件的时候需要Vue
import Vue from 'vue'
 
// 引入vuex插件
import Vuex from 'vuex'
 
// 使用插件
Vue.use(Vuex)
 
// 创建三个vuex插件的核心对象:actions对象、mutations对象、state对象
const actions = {}
const mutations = {}
const state = {}
 
// 简写形式
export default new Vuex.Store({actions,mutations,state})
 
 
/* // 创建store对象(这个store对象是vuex插件中的老大,最核心的对象,这个对象store是用来管理actions对象、mutations对象、state对象。)
const store = new Vuex.Store({
    // 它是一个负责执行某个行为的对象
    actions : actions,
    // 它是一个负责更新的对象
    mutations : mutations,
    // 它是一个状态对象
    state : state
})
 
// 导出store对象(暴露之后,别人想用可以使用import进行引入)
export default store */

3.暴漏vuex核心对象store

在store.js文件中创建核心store对象,并暴露

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue'
import App from './App.vue'
 
Vue.config.productionTip = false
 
// 引入Vuex插件中的核心对象store
import store from './vuex/store'
 
new Vue({
  el : '#app',
  // 一个全新的配置项,以前没有学过:store
  // 加上这个配置项之后,vm以及所有的vc对象上都会多一个属性:$store
  // 以后通过vm.$store或者vc.$store来获取store对象。
  //store : store,
  store,
  render : h => h(App),
})

2.3.3、vuex实现点我加一功能

复制代码
<template>
    <div>
        <h1>数字:{{$store.state.num}}</h1>
        <button @click="plusOne()">点我加1</button>
    </div>
</template>

<script>
    export default {
        name : 'App',
        data() {
            return {
                startNum : 0
            }
        },
        methods: {
            plusOne(){
                // 这里的代码在实际开发中可能会比较复杂。
                // 业务逻辑复杂,代码比较多。
                // 如果你将这些代码放到这里的话,这些业务逻辑代码无法得到复用。
                // 无法在其他组件中使用,在其他组件中使用的时候,你还需要把这些代码再写一遍。
                //this.$store.state.num++
                // 调用vuex的API。
                // dispatch是vuex的API。调用这个方法之后,store对象中的plusOne这个action回调函数会被自动调用。
                // dispatch:分发
                // 交给plusOne这个action去处理这个事儿。
                this.$store.dispatch('plusOne', this.startNum)
            }
        },
    }
</script>
App.vue
复制代码
复制代码
// 引入Vue,因为下面使用Vuex插件的时候需要Vue
import Vue from 'vue'

// 引入vuex插件
import Vuex from 'vuex'

// 使用插件
Vue.use(Vuex)

// 创建三个vuex插件的核心对象:actions对象、mutations对象、state对象
const actions = {
    // N多个action
    // 每一个action都是一个callback(回调函数)
    // 在action这种回调函数中编写复杂的业务逻辑
    // 有个原则:action是专门用来处理业务逻辑,或者说发送AJAX请求的。
    //plusOne : function(){}
    // 简写
    // context参数:context是vuex的上下文(context可以看做是store对象的缩小版)
    // value参数:传过来的数据
    plusOne(context, value){ 
        // 处理业务
        value = value + 1
        // 调用其它的action这个回调函数
        //context.dispatch('otherAction', value)
        // 业务逻辑处理完成之后,继续向下一个环节走,就轮到了数据的更新。
        // 提交上下文环境(所有的事儿都做完了,该最后一步了,更新数据了,怎么办?提交)
        context.commit('PLUS_ONE', value)
    },

    // 这里可能还会有其它的action
    // ...
    /* otherAction(context, value){        
        console.log(6666)
    } */
}
const mutations = {
    // N多个mutation
    // 每一个mutation都是一个callback(回调函数)
    // 每一个mutation这个回调函数的作用就是:更新state
    // 只要state一更新,因为是响应式的,所以页面就重新渲染了。
    // state参数:状态对象
    // value参数:上一环节传过来的数据
    PLUS_ONE(state, value){
        state.num += value
    }
}

// 等同于Vue当中的data(只不过这里我们不叫做数据,叫做状态)
// 状态对象(数据对象),已经做了响应式处理的。
const state = {
    num : 0
}

// 简写形式
export default new Vuex.Store({actions,mutations,state})
vuex/store.js
复制代码

 

posted @   Java小白的搬砖路  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
历史上的今天:
2021-08-16 Servlet中过滤器:放行指定IP
2020-08-16 ServletConfig中的方法
2020-08-16 Servlet的生命周期

喜欢请打赏

扫描二维码打赏

支付宝打赏

点击右上角即可分享
微信分享提示