• 路费学城之 vue


    目录

    路费学城之 vue

    vue笔记

    一、vue 框架内容大纲

    """
    Vue框架:前台界面,页面逻辑
    	1)指令
    	2)实例成员
    	3)组件
    	4)项目开发
    
    DRF框架:数据(接口)
    	1)基础的模块:请求、响应、解析、渲染
    	2)序列化、三大认证
    	3)过滤、搜索、排序、分页
    	4)异常、第三方jwt、restful接口规范
    	
    Luffy项目:前后台分离项目
    	1)项目的登录认证、课程商机销售、项目完成
    	2)短信、支付宝、服务器、上线、redis、celery、git
    """
    

    vue 框架

    """
    1)定义:javascript渐进式框架
    	渐进式:可以控制一个页面的一个标签,也可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目
    
    2)优势:
    	有指令(分支结构,循环结构...),复用页面结构等
    	有实例成员(过滤器,监听),可以对渲染的数据做二次格式化
    	有组件(模块的复用或组合),快速搭建页面
    	
    	虚拟DOM
    	数据的双向绑定
    	单页面应用
    	数据驱动
    	
    3)为什么学习vue:
    	前台框架:Angular(庞大)、React(精通移动端)、Vue(吸取前两者优势,轻量级)
    	Vue一手文档是中文
    	实现前后台分离开发,节约开发成本
    	
    4)如何使用Vue
    	简单使用
    """
    

    Vue环境简单搭建:通过script标签导入vue文件即可

    """
    1)cdn
    <script src="https://cn.vuejs.org/js/vue.js"></script>
    
    2)本地导入
    <script src="js/vue.js"></script>
    """
    

    挂载点el

    """
    /** el: 挂载点
    * 1)一个挂载点只能控制一个页面结构(优先匹配到的结构)
    * 2)挂载点挂载的页面标签严格建议用id属性进行匹配(一般习惯用app)
    * 3)html标签与body标签不能作为挂载点(html和body标签不可以被替换,组件中详细介绍)
    * 4)是否接受vue对象,是外界是否要只有vue对象的内容决定的
    */
    """
    
    <div id="app">
        <div class="d1">
            {{ num }}
        </div>
        <div class="d1">
            {{ num }}
        </div>
    </div>
    <div id="main">
        {{ n }}
    </div>
    
    <script>
     var app = new Vue({
         el: '#app',
         data: {
             num: 100
         }
     });
     console.log(app.$data.num, app.num);
     new Vue({
         el: '#main',
         data: {
             n: app.num
         }
     });
    </script>
    

    插值表达式

    """
     /** 插值表达式
         * 1)空插值表达式:{{ }}
         * 2)中渲染的变量在data中可以初始化
         * 3)插值表达式可以进行简单运算与简单逻辑
         * 4)插值表达式符合冲突解决,用delimiters自定义(了解)
         */
    """
    
    <div id="app">
        <p>{{ info }}</p>
        <p>{{ msg }}</p>
        <p>{{ }}</p>
        <p>{{num}}</p>
        <p>{{num + 10 * 2}}</p>
        <p>{{ msg.length + num }}</p>
        <p>{{ msg[4] }}</p>
        <p>{{ msg.split('')[4] }}</p>
        <p>[{ num }]</p>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                info: '信息',
                msg: 'message',
                num: 10,
            },
            // 控制vue插值表达式符合
            delimiters: ['[{', '}]'],
        })
    </script>
    

    过滤器

    """
    /** 过滤器
         * 1)用实例成员filters来定义过滤器
         * 2)在页面结构中,用 | 来标识使用过滤器
         * 3)过滤方法的返回值就是过滤器过滤后的结果
         * 4)过滤器可以对1~n个变量进行过滤,同时还可以传入辅助的变量,
         *      过滤器方法接受参数是安装传入的位置先后
         */
    """
    
    <body>
        <div id="app">
            <!-- 简单使用:过滤的对象会作为参数传给过滤器 -->
            <p>{{ num | add(20) }}</p>
            <!-- 串联使用:将第一个过滤器结果作为参数给第二个过滤器 -->
            <p>{{ num | add(100) | jump(2) }}</p>
            <!-- 究极使用 -->
            <p>{{ n1, n2 | fn(99, 77) }}</p>
            <!-- 你品,你细品 -->
            <p>{{ n1, n2 | fn(99, 77), n1, n2 | fn(100) }}</p>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                num: 10,
                n1: 66,
                n2: 88
            },
            filters: {
                add: function (a, b) {
                    console.log(a, b);
                    return a + b;
                },
                jump: function (a, b) {
                    return a * b
                },
                fn: function (a, b, c, d) {
                    console.log(a, b, c, d);
                    return a + b + c + d;
                }
            }
        })
    </script>
    
    

    以上所学实例成员(实例属性,自我完成小结)

    {
    el:
    data:
    delimiters:
    filters:
    }
    
    

    文本指令

    """
    /**
    * 1) v-* 是vue指令,会被vue解析,v-text="num"中的num是变量(指令是有限的,不可以自定义)
    * 2)v-text是原样输出渲染内容,渲染控制的标签自身内容会被替换掉(<p v-text="num">123</p>会被num替换)
    * 3)v-html可以解析渲染html语法的内容
    */
    
    
    4)补充
    <!-- js基本数据类型:字符串、数字、布尔、undefined -->
    <p v-text="'abc' + num + 10"></p>
    <p>{{ 'abc' + num + 10 }}</p>
    """
    
    
    <body>
        <div id="app">
            <p>{{ num | add(300) }}</p>
    
            <p v-text="num"></p>
            <p v-text="num">123</p>
    
            <p v-text="info"></p>
            <p v-html="info"></p>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                num: 100,
                info: '<i style="color: red">info内容</i>'
            },
            filters: {
                add: function (a, b) {
                    return a + b;
                }
            }
        })
    </script>
    
    

    事件指令

    """
    /**
     * 一、数据驱动
     *  1)操作是一个功能,使用需要一个方法来控制 2)方法名是变量,所以控制变量就可以控制该方法
     *
     *
     * 二、事件指令
     *  1)在实例成员methods中声明事件方法
     *  2)标签通过事件指令绑定声明的方法: v-on:事件名="事件方法名"
     *      eg: <button v-on:click="btnClick">按钮</button>
     *  3)标签通过事件指令绑定声明的方法,且自定义传参: v-on:事件名="事件方法名()"
     *      eg: <button v-on:click="btnClick()">按钮</button>  不传任何参数
     *      eg: <button v-on:click="btnClick($event)">按钮</button>  传入事件对象,同不写()
     *      eg: <button v-on:click="btnClick(10)">按钮</button>  只传入自定义参数,当然也可以传入事件对象
     */
    """
    
    
    <body>
        <div id="app">
            <button v-on:click="btnClick">{{ btn1 }}</button>
    
            <button v-on:click="btnClick">{{ btn2 }}</button>
            <hr>
    
            <!-- 直接绑定事件名:系统会在触发事件时(点击时)调用事件方法(fn1),传给事件方法一个参数(事件对象) -->
            <button v-on:click="fn1">按钮3</button>
    
            <!-- 绑定的事件名后跟着(),不是主动调用事件方法,而是表示在触发事件调用时,传入的参数全由用户自己决定 -->
            <button v-on:click="fn2($event, 10, 20)">按钮4</button>
    
            <hr>
            <button v-on:click="fn(btn1)">{{ btn1 }}</button>
    
            <button v-on:click="fn(btn2)">{{ btn2 }}</button>
        </div>
    </body>
    <script src="js/vue.js"></script>
    <script>
        // 对比DOM驱动:1)js选择器获取目标标签 2)为目标标签绑定事件 3)在事件中完成相应逻辑
        // var btn = document.getElementsByTagName('button')[0];
        // btn.onclick = function () {
        //     console.log(111111111111);
        // };
        new Vue({
            el: '#app',
            data: {
                btn1: '按钮1',
                btn2: '按钮2',
            },
            methods: {
                btnClick () {
                    console.log(666)
                },
                fn1 (ev) {
                   console.log(ev.clientX, ev.clientY);
                },
                fn2(ev, n1, n2) {
                    console.log(ev, n1, n2);
                    console.log(ev.clientX, ev.clientY);
                },
                fn (msg) {
                    console.log(msg);
                }
            }
        })
    </script>
    
    

    总结

    """
    1、路飞项目所有知识点概况(了解)
    
    2、Vue框架的介绍
    	what:渐进式 javascript 框架
    	where:前后台分离项目的前台开发(pc、移动端)
    	why:有其他框架的优点、轻量、中文API(低学习成本)
    	how:在页面中导入vue环境,用变量控制挂载点,各种指令与实例成员配合
    	
    3、基础实例成员
    	1)挂载点el:id选择器唯一绑定
    	2)插值表达式:{{ 内部可以写基本类型与变量,还可以完成简单运算与逻辑 }}
    	3、标识符:delimiters修改插值表达式符号(了解)
    	4、过滤器:filters自定义过滤器,可以串联使用,可以一次性过滤多个变量
    	5、方法:methods自定义vue控制的方法,给事件指令绑定的
    
    4、基础指令
    	1)v-text:基本同{{}}
    	2)v-html:可以解析html语法的内容
    	3)v-on:
    		v-on:事件="方法"   =>  系统传参,只默认传$event
    		v-on:事件="方法($event, ...)"  => 完全自定义传参,可以手动传入$event
    		
    5、js对象补充:
    	1)对象就可以作为字典,属性名都是字符串,可以省略引号
    	2)属性值时变量同属性名,可以简写
    	3){}中的属性值为函数,称之为方法,也可以简写
    	
    	4)定义的函数,函数名大写,且函数内部有this,代表类
    	5)可以通过 类.prototype.类属性 实现所以对象共享
    	
    """
    
    
    

    二、内容大纲

    """
    1)指令
    	属性指令:v-bind
    	表达指令:v-model
    	条件指令:v-show v-if
    	循环指令:v-for
    	斗篷指令:v-cloak
    	
    2)实例成员
    	计算:computed
    	监听:watch
    	
    3)vue项目环境
    """
    
    

    斗篷指令(了解)

    """
    v-cloak:避免屏幕闪烁
    1)属性选择器,会将v-cloak属性所在的标签隐藏
    2)当vue环境加载后,会将v-cloak属性解析移除,所以内容{{ num }}就会显示出来
    3)而现在vue已经准备完毕,所以用户会直接看到数值10,而不会看到 页面从{{ num }}闪烁成数值10    """
    
    
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
    <div id="app" v-cloak>
        <p>{{ num }}</p>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                num: 10
            },
        })
    </script>
    
    

    属性指令

    """
    /** 属性指令
    * 1)语法:v-bind:属性名="变量"
    * 2)针对不同属性,使用方式稍微有一丢丢区别
    *      i)自定义属性以及title这些,直接赋值的,使用方式如下(t是变量,'o'是常量)
    *          <p v-bind:title="t" v-bind:owen="'o'">段落</p>
    *      ii)class属性(重点):
    *          绑定的变量:值可以为一个类名 "p1",也可以为多个类名 "p1 p2"
    *          绑定的数组:数组的每一个成员都是一个变量
    *          绑定的字典:key就是类名,value是绝对该类名是否起作用
    *      iii)style属性(了解):
    *          绑定的变量:值是一个字典
    */
    """
    
    
    <p v-bind:title="t" v-bind:owen="'o'">段落</p>
    <script>
        new Vue({
            el: '#app',
            data: {
                t: '悬浮提示',
            },
        })
    </script>
    
    
    <!-- 
    a是变量,值就是类名
    b就是类名,不是变量
    c是变量,值为布尔,决定b类是否起作用
    d是变量,值可以为一个类名 'p1' 也可以为多个类名 "p1 p2 ..."
    calss="p1 b p2 p3"
    -->
    <p v-bind:class="[a, {b: c}]" v-bind:class="d"></p> 
    <script>
        let app = new Vue({
            el: '#app',
            data: {
                a: 'p1',
                c: true,
                d: 'p2 p3',
            },
        })
    </script>
    
    
    <p v-bind:style="myStyle"></p>
    <script>
        let app = new Vue({
            el: '#app',
            data: {
                myStyle: {
                     '50px',
                    height: '50px',
                    backgroundColor: 'pink',
                    borderRadius: '50%'
                }
            },
        })
    </script>
    
    
    案例
    <button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1</button>
    <button v-bind:class="{live: isLive == 2}" v-on:click="changeLive(2)">2</button>
    <button v-bind:class="{live: isLive == 3}" v-on:click="changeLive(3)">3</button>
    <script>
        let app = new Vue({
            el: '#app',
            data: {
                isLive: 1,
            },
            methods: {
                changeLive (index) {
                    // this就代表当前vue对象,和app变量等价
                    // app.isLive = index;
                    this.isLive = index;
                }
            }
        })
    </script>  
    
    
    重点:事件指令与属性指令都可以简写
    <!--
    1)v-bind: 可以简写为 :
    2)v-on: 可以简写为 @
    -->
    
    <button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1</button>
    <button :class="{live: isLive == 2}" @click="changeLive(2)">2</button>
    <button :class="{live: isLive == 3}" @click="changeLive(3)">3</button>
    
    

    事件补充

    <style>
        body {
            /* 不允许文本选中 */
            user-select: none;
        }
        .d1:hover {
            color: orange;
            /* 鼠标样式 */
            cursor: pointer;
        }
        /* 只有按下采用样式,抬起就没了 */
        .d1:active {
            color: red;
        }
        /* div标签压根不支持 :visited 伪类 */
        .d1:visited {
            color: pink;
        }
    
        .d2.c1 {
            color: orange;
        }
        .d2.c2 {
            color: red;
        }
        .d2.c3 {
            color: pink;
        }
    </style>
    <div id="app">
        <div class="d1">伪类操作</div>
        <br><br><br>
        <!--
        click: 单击
        dblclick:双击
        mouseover:悬浮
        mouseout:离开
        mousedown:按下
        mouseup:抬起
        -->
        <div :class="['d2', c]" @click="hFn('c1')" @mouseover="hFn('c2')" @mousedown="hFn('c3')">事件处理</div>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                c: '',
            },
            methods: {
                hFn (c) {
                    this.c = c
                }
            }
        })
    </script>
    
    
    

    表单指令

    """
    1)语法:v-model="变量"
    2)v-model绑定的变量控制的其实就是value属性值
    3)v-model要比v-bind:value要对一个监听机制
    4)数据的双向绑定:
    	v-model可以将绑定的变量值映射给表单元素的value
    	v-model还可以将表单元素的新value映射给报道的变量
    """
    
    
    <!-- 两个输入框内容会同时变化 -->
    <input name="n1" type="text" v-model="v1">
    <input name="n2" type="text" v-model="v1">
    <script>
        new Vue({
            el: '#app',
            data: {
                v1: ''
            }
        })
    </script>
    
    

    条件指令

    """
    /**
    * 1)语法:v-show="变量"  |  v-if="变量"
    * 2)两者的区别:
    *      v-show在隐藏标签时,采用display:none渲染标签,标签通过css隐藏
    *      v-if在隐藏标签时,不会渲染在页面上
    *
    * 3)v-if有家族:v-if | v-else-if | v-else
    *      v-if是必须的,必须设置条件
    *      v-else-if可以为0~n个,必须设置条件
    *      v-else可以为0~1个
    *      上方分支成立会屏蔽下方所有分支,从上至下依次类推
    */
    """
    
    
    <div id="app">
        <div>
            <p v-show="isShow">show控制显隐</p>
            <p v-if="isShow">if控制显隐</p>
        </div>
    
        <div>
            <p v-if="0">你是第1个p</p>
            <p v-else-if="0">你是第2个p</p>
            <p v-else>你是第3个p</p>
        </div>
    
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                isShow: false,
            }
        })
    </script>
    
    
    案例
    <style>
        body {
            margin: 0
        }
        button {
             60px;
            line-height: 40px;
            float: right;
        }
        .bGroup:after {
            display: block;
            content: '';
            clear: both;
        }
        .box {
            /* vw: view width  vh: view height*/
             100vw;
            height: 200px;
        }
        .red {
            background-color: red;
        }
        .green {
            background-color: green;
        }
        .blue {
            background-color: blue;
        }
    
        button.active {
            background-color: cyan;
        }
    </style>
    
    <div id="app">
        <div class="bGroup">
            <button :class="{active: isShow === 'red'}" @click="isShow = 'red'">红</button>
            <button :class="{active: isShow === 'green'}" @click="isShow = 'green'">绿</button>
            <button :class="{active: isShow === 'blue'}" @click="isShow = 'blue'">蓝</button>
        </div>
        <div>
            <div v-if="isShow === 'red'" class="box red"></div>
            <div v-else-if="isShow === 'green'" class="box green"></div>
            <div v-else class="box blue"></div>
        </div>
    </div>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                isShow: 'red'
            }
        })
    </script>
    
    

    循环指令

    """
    /**
    * 1)语法:v-for="ele in obj"  obj是被遍历的对象,ele是遍历得到的每一次结果
    * 2)遍历可迭代对象的首要结果,都是可迭代对象容器中的值,其次还可以遍历得到索引及键等数据
    *      字符串:v-for="v in str"  |  v-for="(v, i) in str"
    *      数组:v-for="v in arr"  |  v-for="(v, i) in arr"
    *      对象:v-for="v in obj"  |  v-for="(v, k) in obj"  |  v-for="(v, k, i) in obj"
    * 注:v-for遍历要依赖于一个所属标签,该标签及内部所有内容会被遍历复用
    */
    """
    
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>循环指令</title>
    </head>
    <body>
        <div id="app">
            <!-- 遍历数字
    		5
    		【1】【2】【3】【4】【5】
    		-->
            <p>{{ d1 }}</p>
            <i v-for="e in d1">【{{ e }}】</i>
            <hr>
    
            <!-- 遍历字符串
    		abc
    		【a】【b】【c】
    		【0a】【1b】【2c】
    		-->
            <p>{{ d2 }}</p>
            <i v-for="e in d2">【{{ e }}】</i>
            <i v-for="(e, i) in d2">【{{ i }}{{ e }}】</i>
            <hr>
    
            <!-- 遍历数组
    		[ 1, 3, 5 ]
    		【1】【3】【5】
    		【01】【13】【25】
    		-->
            <p>{{ d3 }}</p>
            <i v-for="e in d3">【{{ e }}】</i>
            <i v-for="(e, i) in d3">【{{ i }}{{ e }}】</i>
            <hr>
    
            <!-- 遍历对象
    		{ "name": "Bob", "age": 17.5, "gender": "男" }
    		【Bob】【17.5】【男】
    		【name-Bob】【age-17.5】【gender-男】
    		【name-Bob-0】【age-17.5-1】【gender-男-2】
    		-->
            <p>{{ d4 }}</p>
            <i v-for="e in d4">【{{ e }}】</i>
            <i v-for="(e, k) in d4">【{{ k }}-{{ e }}】</i>
            <i v-for="(e, k, i) in d4">【{{ k }}-{{ e }}-{{ i }}】</i>
            <hr>
    
        </div>
    </body>
    <script>
        new Vue({
            el: '#app',
            data: {
                d1: 5,
                d2: 'abc',
                d3: [1, 3, 5],
                d4: {
                    name: "Bob",
                    age: 17.5,
                    gender: "男"
                }
            }
        })
    </script>
    
    
    
    商品循环案例
    <style>
        .box {
             280px;
            border: 1px solid #eee;
            border-radius: 5px;
            overflow: hidden; /* 隐藏超出父级显示范围外的内容 */
            text-align: center; /* 文本相关的属性大多默认值是inherit */
            float: left;
            margin: 10px;
        }
        .box img {
             100%;
        }
    </style>
    
    <div id="app">
        <div class="box" v-for="obj in goods">
            <img :src="obj.img" alt="">
            <p>{{ obj.title }}</p>
        </div>
    </div>
    
    <script>
        let goods = [
            {
                "img": "https://***1.jpg",
                "title": "纯种拆家专家1"
            },
            {
                "img": "https://***2.jpg",
                "title": "纯种拆家专家2"
            },
        ];
        
        new Vue({
            el: '#app',
            data: {
                goods,
            }
        })
    </script>
    
    

    面试题:todolist

    js的Array操作
    """
    尾增:arr.push(ele)  
    首增:arr.unshift(ele)
    尾删:arr.pop()
    首删:arr.shift()
    增删改插:arr.splice(begin_index, count, args)
    """
    
    
    前台数据库
    """
    // 存
    // 持久化化存储,永远保存
    localStorage.name = "Bob";
    // 持久化化存储,生命周期同所属标签(页面),页面关闭,重新打开就会丢失
    sessionStorage.name = "Tom";
    
    // 取
    console.log(localStorage.name);
    console.log(sessionStorage.name);
    
    // 清空
    localStorage.clear();
    sessionStorage.clear();
    
    // 短板:只能存储字符串,所有对象和数组需要转换为json类型字符串,再进行存储
    let a = [1, 2, 3];
    localStorage.arr = JSON.stringify(a);
    let b = JSON.parse(localStorage.arr);
    console.log(b);
    """
    
    
    案例:留言板
    <style>
        li:hover {
            color: red;
            cursor: pointer;
        }
    </style>
    
    <div id="app">
        <form>
            <input type="text" v-model="info">
            <button type="button" @click="sendInfo">留言</button>
        </form>
        <ul>
            <li v-for="(info, index) in info_arr" @click="deleteInfo(index)">{{ info }}</li>
        </ul>
    </div>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                info: '',
                // 三目运算符: 条件 ? 结果1 : 结果2
                info_arr: localStorage.info_arr ? JSON.parse(localStorage.info_arr) : [],
            },
            methods: {
                sendInfo () {
                    // 完成留言:将info添加到info_arr
                    // 增 push unshift | 删 pop shift
                    if (this.info) {
                        // 留言
                        this.info_arr.push(this.info);
                        // 清空输入框
                        this.info = '';
                        // 前台数据持久化(缓存)
                        localStorage.info_arr = JSON.stringify(this.info_arr);
                    }
                },
                deleteInfo(index) {
                    // 删
                    this.info_arr.splice(index, 1);
                    // 同步给数据库
                    localStorage.info_arr = JSON.stringify(this.info_arr);
                }
            }
        })
    </script>
    
    

    小结

    """
    1、v-cloak斗篷指令
    2、属性指令
    	v-bind:title="变量"
    	:class="变量" | :class="[变量1, ..., 变量n]"  |  :class="{类名: 布尔变量}"
    	:style="字典变量"
    3、事件:@click @dblclick @mouseover|out|down|up
    	鼠标单击、双击、悬浮、移开、按下、抬起
    4、表单指令:
    	v-model绑定变量控制value属性,可以实现双向绑定
    5、条件指令:
    	v-show | v-if
    	v-if | v-else-if | v-else
    6、循环指令:
    	字符串:v-for="v in str"  |  v-for="(v, i) in str"
        数组:v-for="v in arr"  |  v-for="(v, i) in arr"
        对象:v-for="v in obj"  |  v-for="(v, k) in obj"  |  v-for="(v, k, i) in obj"
        
    7、Array操作
    	arr.push(ele)  arr.unshift(ele)
    	arr.pop()  arr.shift()
    	arr.splice(begin_index, count, args)
    
    8、前台数据库
    	localStorage | sessionStorage
    	1)操作就类似于obj,直接 .key 语法访问 value
    	2)localStorage永久存储
    	3)sessionStorage生命周期同所属页面标签
    	
    """
    
    
    

    三、内容大纲

    """
    1)computed
    2)watch
    3)项目环境
    4)项目开发:请求生命周期、组件、组件的生命周期、路由...
    """
    
    

    字符串补充

    """
    1)双引号:
    	"前缀" + 变量 + "后缀"
    	
    2)单引号:
    	'前缀' + 变量 + '后缀'
    
    3)反引号:
    	`前缀${变量}后缀`
    	注:在反引号中可以用 ${} 来包裹变量,实现字符串拼接
    """
    
    

    实例成员:计算属性

    """
    /** 计算属性:
    * 1)其实就是vue中的方法属性,方法名可以作为属性来使用,属性值为方法的返回值
    * 2)在computed中声明的方法属性,不能在data中重复声明,比data中声明的属性要多出写逻辑的地方
    * 3)方法属性,自带监听机制,在方法属性中出现的变量,都会被监听,一旦有任何被监听的变量值发生更新,
    *      方法属性都会被调用更新方法属性的值
    * 4)方法属性一定要在页面中渲染一次,方法属性采用意义,多次渲染,方法属性只会被调用一次
    * 案例:计算器
    * 方法属性的应用场景:一个变量依赖于多个变量,且需要进行一定的逻辑运算
    */
    """
    
    
    <div id="app">
        <!-- type="number"表示只能写数字 -->
        <input type="number" v-model="num1" max="100" min="0">
        +
        <input type="number" v-model="num2" max="100" min="0">
        =
        <button>{{ sum }}</button>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                // sum: '',  // 重复声明
                num1: '',
                num2: '',
            },
            computed: {
                sum () {
                    // num1和num2都在该方法属性中,所以有一个更新值,该方法都会被调用
                    if (this.num1 && this.num2) {
                        return +this.num1 + +this.num2;  // +this.num1是将字符串快速转换澄数字
                    }
                    return '结果';
                }
            }
        })
    </script>
    
    
    

    监听属性

    """
    /**
    * 1)watch中不定义属性,只是监听属性,所以方法的返回值没有任何意义,只是监听变量值是否发生更新
    * 2)watch中的方法名,就是被监听的属性(方法名同被监听属性名)
    * 3)被监听的变量值一旦发生更新,监听方法就会被调用
    * 应用场景:
    *      i)k线图:股票数据变化,页面的k线图重新渲染(需要逻辑将数据转换为图形)
    *      ii)拆分姓名:录入姓名,拆分为姓和名(需要逻辑将一个数据拆分为多个数据)
    */
    """
    
    
    <div id="app">
        姓名:<input type="text" v-model="full_name">
        <hr>
        姓:<button>{{ first_name }}</button>
        名:<button>{{ last_name }}</button>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                full_name: '',
                first_name: '未知',
                last_name: '未知'
            },
            watch: {
                full_name () {
                    if (this.full_name) {
                        // 只是实现简易的拆分逻辑
                        this.first_name = this.full_name.split('')[0];
                        this.last_name = this.full_name.split('')[1];
                    } else {
                        this.first_name = '未知';
                        this.last_name = '未知';
                    }
                }
            }
        })
    </script>
    
    
    

    vue的项目开发

    环境:安装vue的脚手架cli环境

    """
    node 	~~ 		python
    npm 	~~		pip
    
    python:c语言编写,解释执行python语言的
    node:c++语言编写,解释执行JavaScript语言的
    npm类似于pip,是为node环境安装额外功能的
    
    """
    
    """
    1)官网下载并安装node,附带npm
    	https://nodejs.org/zh-cn/
    2)换源:将npm欢迎为cnpm
    	npm install -g cnpm --registry=https://registry.npm.taobao.org
    3)安装vue脚手架	
    	cnpm install -g @vue/cli
    注:如果第二三步异常,基本都是由网络导致的,可以重新执行第二三步,如果一直有问题,可以清理缓存后重复
    	npm cache clean --force
    """
    
    

    项目创建:在终端中创建

    各插件作用
    Babel:将ES6语法解析为ES5语法给浏览器
    Router:前台路由
    Vuex:前台仓库,相当于单例,完成个组件间传参的
    
    

    项目移植:将公司代码在自己电脑上跑起来

    """
    1)拷贝出环境 node_modules 意外的文件与文件夹到目标文件夹
    2)终端进入目标文件夹所在位置
    3)执行:npm install 重新构建依赖(npm可以用cnpm替换)
    """
    
    

    pycharm配置并启动vue项目

    1) 用pycharm打开vue项目
    2) 添加配置npm启动
    
    

    vue项目目录结构分析

    ├── v-proj
    |	├── node_modules  	// 当前项目所有依赖,一般不可以移植给其他电脑环境
    |	├── public			
    |	|	├── favicon.ico	// 标签图标
    |	|	└── index.html	// 当前项目唯一的页面
    |	├── src
    |	|	├── assets		// 静态资源img、css、js
    |	|	├── components	// 小组件
    |	|	├── views		// 页面组件
    |	|	├── App.vue		// 根组件
    |	|	├── main.js		// 全局脚本文件(项目的入口)
    |	|	├── router
    |	|	|	└── index.js// 路由脚本文件(配置路由 url链接 与 页面组件的映射关系)
    |	|	└── store	
    |	|	|	└── index.js// 仓库脚本文件(vuex插件的配置文件,数据仓库)
    |	├── README.md
    └	└── package.json等配置文件
    
    

    vue组件(.vue文件)

    """
    注:pycharm安装vue.js插件,就可以高亮显示vue文件了
    
    1)一个.vue文件就是一个组件
    2)组件都是由三部分组成:html结构、js逻辑、css样式
        html结构都是在template标签中,页面结构有且只有一个根标签(template一级结构下)
        js逻辑都是在script标签中,必须设置导出,export default {...}
        css样式都是在style标签中,必须设置scoped属性,是样式组件化
    """
    
    
    <template>
        <div class="first-cp">
             <h1>第一个组件</h1>
        </div>
    </template>
    
    <script>
        // .vue文件类似于模块,可以直接相互导入,所以在组件内部要设置导出
        export default {
    
        }
    </script>
    
    <style scoped>
        /* scoped可以使样式组件化,只在自己内部起作用 */
    
    </style>
    
    

    全局脚本文件main.js(项目入口)

    """
    1)main.js是项目的入口文件
    2)new Vue()就是创建根组件,用render读取一个.vue文件,$mount渲染替换index.html中的占位
    3)项目所依赖的环境,比如:vue环境、路由环境、仓库环境、第三方环境、自定义环境都是在main.js中完成
    """
    
    
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount('#app')
    
    
    
    改写
    import Vue from 'vue'  // 加载vue环境
    import App from './App.vue'  // 加载根组件
    import router from './router'  // 加载路由环境
    import store from './store'  // 加载数据仓库环境
    
    Vue.config.productionTip = false;  // tip小提示
    
    import FirstCP from './views/FirstCP'
    new Vue({
        el: '#app',
        router: router,
        store: store,
        render: function (readVueFn) {
            return readVueFn(FirstCP);  // 读取FirstCP.vue替换index.html中的占位
        }
    });
    
    
    

    路由与根组件(重点)

    路由核心配置:router/index.js

    // import 别名 from '文件'
    import Home from '../views/Home'
    import About from '../views/About'
    import First from '../views/FirstCP'
    
    // 路由配置
    // 1)当用户在浏览器中访问的路由是 / ,router插件就会加载 Home.vue文件,同理 /about 就是 About.vue文件
    // 2)将加载的 Home.vue文件 或者 About.vue文件,去替换App.vue文件中的 <router-view />占位符
    // 3)用redirect配置来实现路由的重定向
    const routes = [
        {
            path: '/',
            name: 'Home',
            component: Home
        },
        {
            path: '/home',
            redirect: '/',  // 路由的重定向
        },
        {
            path: '/about',
            name: 'About',
            component: About
        },
        {
            path: '/first',
            name: 'First',
            component: First
        }
    ];
    
    
    根组件占位渲染页面组件
    <!--
    1)App.vue是项目的根组件,是唯一由main.js加载渲染的组件,就是替换index.html页面中的<div id="app"></div>的占位标签
    2)实际开发中App.vue文件中,只需要书写下方五行代码即可(可以额外增加其他代码)
    3)router-view是一个占位标签,由router插件控制,可以在router的配置文件中进行配置
    4)router-view就是根据router在index.js中配置的路由关系被 指定路径 匹配 指定页面组件 渲染
        router-view或被不同的页面组件替换,就形成了页面跳转
    -->
    <template>
        <div id="app">
            <!-- 前台路由占位标签,末尾的/代表单标签的结束 -->
            <router-view />
        </div>
    </template>
    
    

    页面组件渲染小组件(重点)

    页面组件作为父组件:views/*.vue

    <template>
        <div class="home">
            <!-- vue项目下的html是支持大小写,且区分大小写 -->
            <Nav />
        </div>
    </template>
    
    <script>
        // 父组件加载子组件:父组件通常是页面组件,是被一个个小组件这些子组件组装成的页面
        // 1)导入语法要在 export default{} 之上完成
        // 2)@符合标识 项目src文件夹 绝对路径
        // 3)要在export default{} 的括号中用 components 注册
        // 4)在该组件的模板中就可以渲染子组件了(html代码中是区别大小写的)
        // 5)步骤:i)导入子组件 ii)注册子组件 iii)使用子组件
        import Nav from '@/components/Nav'
    
        export default {
            components: {
                Nav,
            }
        }
    </script>
    
    <style scoped>
        .home {
             100vw;
            height: 100vh;
            background-color: orange;
        }
    </style>
    
    

    导航栏小组件(封装路由跳转):components/*.vue

    <template>
        <div class="nav">
            <img src="" />
            <ul>
                <li>
                    <!-- router控制的路由,不是用a标签完成跳转:
                        1)a标签会刷新页面,错误的
                        2)router-link标签也能完成跳转,且不会刷新页面,就是router提供的a标签(最终会被解析为a标签,还是用a来控制样式)
    					3)router-link标签的to属性控制跳转路径,由两种方式
                            i) to="路径字符串"
                            ii :to="{name: '路由名'}"
                    -->
                    <a href="/">主页</a>
                </li>
                <li>
                    <router-link to="/about">关于页</router-link>
                </li>
                <li>
                    <!-- to="字符串",v-bind:to="变量",可以简写为 :to="变量" -->
                    <router-link :to="{name: 'First'}">第一页</router-link>
                </li>
            </ul>
        </div>
    </template>
    
    <style scoped>
        .nav {
             100%;
            height: 80px;
            background: rgba(0, 0, 0, 0.3);
        }
        img {
             200px;
            height: 80px;
            background: tan;
            float: left;
        }
        ul {
            float: left;
            list-style: none;
            margin: 0;
            padding: 0;
            height: 80px;
            background: pink;
        }
        ul li {
            float: left;
            height: 80px;
            padding: 30px 20px 0;
        }
        a {
            color: black;
        }
    </style>
    
    

    总结

    """
    1)计算属性:computed
    	定义方法属性,返回值为属性值,方法内的变量都会被监听
    	案例:计算器
    	
    2)监听属性:watch
    	监听与方法名同名的属性,被监听的数据更新调用方法
    	案例:拆分姓名,k线图
    	
    3)vue项目环境:
    	node -> npm -> cnmp -> vue/cli
    	
    4)新建vue项目:在当前终端所在目录下
    	vue create 项目
    	
    5)pycharm配置项目启动
    	在pycharm中设置npm启动
    	
    6)项目目录结构
    
    7)组件:vue文件
    
    8)入口文件:main.js
    
    9)根组件、页面组件、小组件 与 路由关系(router-view、router-link)
    """
    
    

    四、内容大纲

    """
    1)路由:逻辑跳转、路由传参
    2)项目组件的数据局部化处理:data: {} => data: function(){ return {} } => data(){ return{} }
    3)组件的声明周期
    4)组件间通信
    5)各种第三方插件:vuex、axios、element-ui、(jq+bs) 
    """
    
    

    项目初始化

    """
    1)根组件:App.vue
    <template>
        <div id="app">
            <router-view />
        </div>
    </template>
    
    2)路由配置:router/index.js
    const routes = [
        {
            path: '/',
            name: 'Home',
            component: Home
        }
    ];
    
    3)组件:views和components文件夹
    	i)删除除Home.vue以为的所有组件
    	ii)初始化Home.vue
    	<template>
            <div class="home">
            </div>
        </template>
    
    4)分类管理资源:assets文件夹
    	建立img、css、js子文件夹,删除原来的资源
    	
    5)如果要修改页面标签图标
    	替换public文件夹下的favicon.ico图片文件
    """
    
    

    组件数据局部化处理

    """
    1)不管页面组件还是小组件,都可能会被多次复用
    2)复用组件的原因,其实就是复用组件的 页面结构、页面样式、页面逻辑
    3)但是页面上的数据需要区分(被复用的两个组件数据多少是有区别的),所以组件的数据要做局部化处理
    4)借助函数可以产生局部作用域的特点,为每一次复用组件产生一个独立的作用域
    语法:
    data () {
    	return {
    		// 数据们
    	}
    }
    """
    
    
    子组件
    <template>
        <div class="beat" @click="count += 1">
            {{ count }}下
        </div>
    </template>
    
    <script>
        export default {
            name: "Beat",
            // 不管是页面组件还是小组件,都可能被复用,页面结构与样式都可以采用一套,但是数据一定要相互独立
            data () {
                return {
                    count: 0
                }
            }
        }
    </script>
    
    <style scoped>
        .beat {
             100px;
            height: 100px;
            background-color: orange;
            text-align: center;
            line-height: 100px;
            border-radius: 50%;
        }
    </style>
    
    
    
    父组件
    <template>
        <div class="home">
            <Beat/>
            <Beat/>
        </div>
    </template>
    <script>
        import Beat from '@/components/Beat'
        export default {
            components: {
                Beat,
            }
        }
    </script>
    
    

    路由逻辑跳转

    """
    1)很多时候,我们需要通过普通按钮的逻辑,或是直接在某些逻辑中完成页面的跳转
    2)可以通过在逻辑中用 this.$router.push() 来完成前往目标页,两种语法如下
    	this.$router.push('路径')
    	this.$router.push({name: '路由名'})
    3)在做移动端项目时,没有像浏览器那样的前进后台键,页可以用 this.$router.go() 来完成前进后退,语法如下
    	前进后退:this.$router.go(正负整数),正式代表前进,负数代表后台,数值就是步长
    """
    
    
    案例
    <template>
        <div class="home">
            <Nav/>
            <h1>主页</h1>
            <button @click="goPage('/first')">前往第一页</button>
            |
            <button @click="goPage('/second')">前往第二页</button>
            |
            <button @click="goBack(-1)">后退一页</button>
            |
            <button @click="goBack(-2)">后退二页</button>
            |
            <button @click="goBack(1)">前进一页</button>
        </div>
    </template>
    
    <script>
        import Nav from '@/components/Nav'
    
        export default {
            methods: {
                goPage(path) {
                    // 可以通过 this.$router 完成逻辑跳转
                    this.$router.push();
                },
                goBack(num) {
                    // 一般在移动端项目上运用
                    this.$router.go(num);  
                }
            },
            components: {
                Nav,
            }
        }
    </script>
    
    

    组件传参

    父传子

    """
    一、组件传参 - 父传子
    1)在子组件内部通过props设置组件的自定义属性
        props: ['abc', 'goods']
    2)在父组件渲染子组件是对自定义属性赋值即可
        <GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods"/>
    """
    
    
    子组件
    <template>
        <div class="goods-box">
            <img :src="goods.img" alt="">
            <p>{{ goods.title }}</p>
        </div>
    </template>
    
    <script>
        export default {
            name: "GoodsBox",
            // 在组件内部通过props定义组件的自定义属性
            props: ['abc', 'goods'],
        }
    </script>
    
    <style scoped>
        .goods-box {
             260px;
            height: 300px;
            border: 1px solid black;
            border-radius: 5px;
            margin: 20px;
            float: left;
            overflow: hidden;
            text-align: center;
        }
        img {
             260px;
            height: 260px;
        }
    </style>
    
    
    父组件
    <template>
        <div class="goods">
            <div class="main">
                <!-- 在使用子组件是对自定义属性赋值即可 -->
                <GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods" />
            </div>
        </div>
    </template>
    <script>
        import GoodsBox from "../components/GoodsBox";
    
        let goods_list = [
            {
                img: require('@/assets/img/001.jpg'),
                title: '小猫',
            },
            {
                img: require('@/assets/img/002.jpg'),
                title: '小猫儿',
            },
            {
                img: require('@/assets/img/003.jpg'),
                title: '小狗',
            },
            {
                img: require('@/assets/img/004.jpg'),
                title: '小狗儿',
            },
        ];
    
        export default {
            name: "Goods",
            data () {
                return {
                    goods_list,
                }
            },
            components: {
                GoodsBox,
            },
        }
    </script>
    
    
    

    子传父

    """
    二、组件传参 - 子传父
    前提:子组件是被父组件渲染的,所以子组件渲染要晚于父组件
    1)子组件一定要满足一个条件,才能对父组件进行传参(某个时间节点 === 某个被激活的方法)
        eg:i)子组件刚刚加载成功,给父组件传参 ii)子组件某一个按钮被点击的时刻,给父组件传参 iii)子组件要被销毁了,给父组件传参
    
    2)在子组件满足条件激活子组件的方法中,对父组件发生一个通知,并将数据携带处理(自定义组件事件)
        <div class="goods-box" @click="boxClick"></div>
        methods: {
            boxClick () { this.$emit('receiveData', this.goods.title, '第二个数据', '第三个数据') }
        }
    
    3)在父组件渲染子组件时,为自定义事件绑定方法
        <GoodsBox @receiveData="recFn"/>
    
    4)在父组件实现绑定方法时,就可以拿到子组件传参的内容(接收到了通知并在父组件中相应)
        recFn(title, data2, data3) {
            console.log('接收到了' + title);
        }
    
    组件标签不能绑定系统定义的事件,没有意义,子组件的事件都是在自己内部完成
    """
    
    
    子组件
    <template>
        <div class="goods-box" @click="boxClick">
            <img :src="goods.img" alt="">
            <p>{{ goods.title }}</p>
        </div>
    </template>
    
    <script>
        export default {
            props: ['abc', 'goods'],
            methods: {
                boxClick () {
                    // 通知父级 - 自定义组件的事件
                    this.$emit('receiveData', this.goods.title)
                }
            }
        }
    </script>
    
    
    父组件
    <template>
        <div class="goods">
            <div class="main">
                <!-- 实现自定义事件,接收子组件通知的参数 -->
                <GoodsBox v-for="goods in goods_list" @receiveData="recFn"/>
            </div>
        </div>
    </template>
    <script>
        import GoodsBox from "../components/GoodsBox";
        export default {
            name: "Goods",
            data () {
                return {
                    goodsTitle: '哪个',
                }
            },
            methods: {
                recFn(title) {
                    console.log('接收到了' + title);
                    this.goodsTitle = title;
                }
            },
            components: {
                GoodsBox,
            },
        }
    </script>
    
    
    

    组件的生命周期钩子

    """
    一、组件的生命周期:一个组件从创建到销毁的整个过程
    二、生命周期钩子:在一个组件生命周期中,会有很多特殊的时间节点,且往往会在特定的时间节点完成一定的逻辑,特殊的事件节点可以绑定钩子
    注:钩子 - 提前为某个事件绑定方法,当满足这个事件激活条件时,方法就会被调用 | 满足特点条件被回调的绑定方法就称之为钩子
    """
    
    
    <template>
        <div class="goods">
            <Nav />
        </div>
    </template>
    <script>
        import Nav from "../components/Nav";
        export default {
            name: "Goods",
            components: {
                Nav,
            },
            beforeCreate() {
                console.log('该组件要被加载了')
            },
            created() {
                console.log('该组件要被加载成功了')
            },
            updated() {
                console.log('数据更新了')
            },
            destroyed() {
                console.log('该组件销毁了')
            }
        }
    </script>
    
    
    

    路由传参

    """
    路由传参:
    一、通过url正则传递数据
    i)设置
        路由: path: '/goods/detail/:pk'   |   '/goods/:pk/detail/:xyz'
        请求: '/goods/detail/任意字符'    |    '/goods/任意字符/detail/任意字符'
    ii)如何传
        <router-link :to="`/goods/detail/${pk}`"></router-link>
        this.$router.push(`/goods/detail/${pk}`)
    
    iii)如何取
        this.$route对象是管理路由参数的,传递的参数会在this.$route.params字典中
        this.$route.params.pk
    
    二、通过url参数传递数据
    i)设置
        路由: path: '/goods/detail'
        请求: '/goods/detail?pk=数据'
    ii)如何传
        <router-link :to="`/goods/detail?pk=${pk}`"></router-link>
        <router-link :to="{name:'GoodsDetail', query:{pk: pk}}"></router-link>
    
        this.$router.push(`/goods/detail?pk=${pk}`)
        this.$router.push({name:'GoodsDetail', query:{pk: pk}})
    
    iii)如何取
        this.$route对象是管理路由参数的,传递的参数会在this.$route.query字典中
        this.$route.query.pk
    """
    
    

    第一种

    配置:router/index.js
    const routes = [
        {
            path: '/goods/detail/:pk',
            name: 'GoodsDetail',
            component: GoodsDetail
        },
    ]
    
    
    传递:GoodsBox.vue
    <router-link class="goods-box" :to="`/goods/detail/${goods.pk}`">
        <img :src="goods.img" alt="">
        <p>{{ goods.title }}</p>
    </router-link>
    
    <!------------------- 或者 ------------------->
    
    <div class="goods-box" @click="goDetail(goods.pk)">
        <img :src="goods.img" alt="">
        <p>{{ goods.title }}</p>
    </div>
    <script>
        export default {
            name: "GoodsBox",
            methods: {
                goDetail (pk) {
                    this.$router.push(`/goods/detail/${pk}`);
                }
            }
        }
    </script>
    
    
    接收:GoodsDetail.py
    <script>
        export default {
            name: "GoodsDetail",
            data () {
                return {
                    pk: '未知',
                }
            },
            // 通常都是在钩子中获取路由传递的参数
            created() {
                this.pk = this.$route.params.pk || this.$route.query.pk;
            }
        }
    </script>
    
    

    第二种

    配置:router/index.js
    const routes = [
        {
            path: '/goods/detail',
            name: 'GoodsDetail',
            component: GoodsDetail
        },
    ]
    
    
    传递:GoodsBox.vue
    <router-link class="goods-box" :to="`/goods/detail?pk=${goods.pk}`">
        <img :src="goods.img" alt="">
        <p>{{ goods.title }}</p>
    </router-link>
    
    <!------------------- 或者 ------------------->
    
    <div class="goods-box" @click="goDetail(goods.pk)">
        <img :src="goods.img" alt="">
        <p>{{ goods.title }}</p>
    </div>
    <script>
        export default {
            name: "GoodsBox",
            methods: {
                goDetail (pk) {
                    // this.$router.push(`/goods/detail?pk=${goods.pk}`);
                    
                    // 或者
                    this.$router.push({
                        name: 'GoodsDetail',
                        query: {
                            pk,
                        }
                    });
                }
            }
        }
    </script>
    
    
    接收:GoodsDetail.py
    <script>
        export default {
            name: "GoodsDetail",
            data () {
                return {
                    pk: '未知',
                }
            },
            // 通常都是在钩子中获取路由传递的参数
            created() {
                this.pk = this.$route.params.pk || this.$route.query.pk;
            }
        }
    </script>
    
    

    全家配置自定义css与js

    global.css
    html, body {
        margin: 0;
    }
    
    a {
        color: black;
        text-decoration: none;
    }
    
    ul {
        margin: 0;
        padding: 0;
    }
    
    
    settings.js
    export default {
        base_url: 'https://127.0.0.1:8000'
    }
    
    
    main.js
    //1) 配置全局css
    import '@/assets/css/global.css'
    // import global_css from '@/assets/css/global.css'  // 资源需要用变量保存,方便以后使用
    // require('@/assets/css/global.css')
    // let global_css = require('@/assets/css/global.css')  // 资源需要用变量保存,方便以后使用
    
    
    // 2) 配置自定义js设置文件
    import settings from '@/assets/js/settings.js'
    Vue.prototype.$settings = settings;
    // 在任何一个组件中的逻辑,可以通过 this.$settings访问settings.js文件的{}数据
    
    

    小结

    """
    项目:
    	环境;node -> npm -> cnpm -> vue/cli
    	创建:vue create proj
    	配置:配置npm启动项
    	项目目录结构:依赖、环境、入口、核心代码们
    	
    组件:
    	构成:template + script + style
    	导入:import 别名 from '路径'
    	父加子:1)导入 2)注册 3)使用
    	组件数据:组件化处理 data(){ return {} }
    	传参:父传子 - 自定义组件属性  |  子传父 - 自定义组件事件
    	生命周期钩子:created() { //完成后台请求等 }
    
    路由:
    	根组件中的页面占位:<router-view />
    	导航栏中的页面跳转:<router-link to=""></router-link>
    	代码中的逻辑跳转:this.$router.push() | this.$router.go()
    	路由传参:两种方式
    	两个路由对象:
    		this.$router - 控制路由跳转
            this.$route - 控制路由数据
    """
    
    

    五、内容大纲

    """
    第三方插件:
    1)vuex:组件间交互的(移动端)
    2)axios - 前后台(django):ajax
    3)element-ui:页面布局
    4)jq+bs:jQuery+BootStrap
    """
    
    

    vuex插件:可以完成任意组件间信息交互(移动端) - 了解

    """
    1)vuex是实现任何组件间的信息交互的,可以理解为全局的一个单例,为任何一个组件共享vue仓库里的数据
    2)在任何一个组件的逻辑里,都可以访问仓库
    	i)现在仓库里(store/index.js)定义变量,用来存储共享数据
    	state: {
            info: '共享数据的初始值'
        },
        ii)在组件逻辑中获取仓库值
        let 变量 = this.$store.state.info
        iii)在组件逻辑中更新仓库值
        this.$store.state.info = '新值'
    
    注:vuex通常运用在开发移动端项目,pc端项目可以用localStorege和localStorege数据库来替换
    原因:vuex中的数据,会在页面刷新后,重置到store/index.js配置的默认值
    """
    
    

    前端存储数据大汇总

    """
    1)cookie:以字符串形式存储,数据有过期时间(过期时间到,数据失效吗,否则永远有效)
    
    2)localStorage:以对象形式存储,数据永久保存
    
    3)sessionStorage:以对象形式存储,生命周期同所属页面标签(页面不关闭,数据就有效)
    
    4)vuex(store):以对象形式存储,当页面刷新数据就重置(移动端不能刷新,所以只有应用大退才会重置)
    """
    
    

    前后台交互方式(重点)

    """
    1)form表单方式
    	i)get | post 两种请求方式,get请求包含直接在浏览器中输入url回车后发送的请求
    	ii)该方式的特点是一定会发生页面的跳转(刷新页面叫本页跳转) - 后台决定页面路由
    	
    2)ajax异步方式
    	i)get | post | patch | put | delete 等众多请求方式,请求的目的都是异步获取后台的数据
    	ii)该方式的特点是不会刷新页面,只是得到新的数据,前台自己完成页面的局部刷新、整体刷新、页面跳转 - 前台决定页面路由
    	
    注:
    i)前后台不分离项目,采用form表单请求,可以完成页面跳转,同步ajax异步请求完成页面局部刷新
    ii)前后台分离项目,不采用form表单请求,页面刷新、页面跳转的请求,都是由ajax完成,只不过页面跳转,后台相应的是跳转的目标url,前台再自己完成跳转
    
    iii)前后台分离项目,前台也会出现大量的form表单,但是form表单的提交按钮,走的不是form表单的submit提交,而是ajax请求
    """
    
    

    axios插件:完成前后台ajax交互的

    """
    1)安装:在前端项目根目录下的终端
    cnpm install axios
    
    2)项目配置:main.js
    import axios from 'axios'
    Vue.prototype.$axios = axios;
    
    3)在任何一个组件的逻辑中,都可以访问 this.$axios()
    beforeMount() {
    	// 请求后台
    	this.$axios({
        	url: this.$settings.base_url + '/test/',
            method: 'delete',
        })
    }
    """
    
    

    同源策略 - 跨域问题

    """
    一、django默认是同源策略,所以前后台分离项目,访问django会出现CORS跨域问题的报错
    
    二、什么叫跨域
    i)ip不同:前后台(两个服务器)不在一台主机上运行的
    ii)port不同:前后台(两个服务器)是相互独立的,运行在不同的端口之上
    iii)协议不同:http与https之间也同样是跨域问题
    注:三者满足一个,就是跨域
    
    三、解决跨域
    i)伪装:将前台请求伪装成后台自己对自己发生的请求
    ii)后台主动允许跨域:后台配置允许跨域即可(在响应头中处理)
    
    四、Django解决跨域
    i)安装模块:
    	pip install django-cors-headers
    ii)注册app:
    INSTALLED_APPS = [
    	...
    	'corsheaders'
    ]
    iii)添加中间件
    MIDDLEWARE = [
    	...
    	'corsheaders.middleware.CorsMiddleware'
    ]
    iv)允许跨域源
    CORS_ORIGIN_ALLOW_ALL = True
    """
    
    

    前后台分离项目交互流程

    """
    1)启动前后台项目
    
    2)前台配置页面路由,渲染前台页面 | 后台配置数据路由,响应数据(处理好跨域问题)
    
    3)前台通过ajax请求后台接口
    	i)将前台数据提交给后台
    	ii)得到后台的响应结果
    	iii)根据响应结果的数据,最后完成页面的局部刷新、整体刷新、页面跳转
    """
    
    

    异步请求细节

    """
    1)vue框架用axios完成ajax异步请求
    	语法:this.$axios().then().catch();
        解读:$axios()是请求逻辑 | then()是正常响应逻辑 | catch()是错误响应逻辑
        具体语法:
        this.$axios({
        	url: '后台接口链接',
        	method: '请求方式',
        	params: {},  // url拼接参数
        	data: {},  // 数据包参数
        	headers: {}  // 请求头参数
        }).then(response => {
        	// response是http状态2xx的响应结果,响应数据是response.data
        }).catch(error => {
        	// error是http状态4xx、5xx的响应结果,错误响应对象是error.response,错误响应数据是error.response.data
        })
    
    2)前台提交数据的两种方式:
    	i)url拼接参数:
    		所有请求都拥有的提交数据的方式
    		该方式会将数据都在请求url后用?拼接的方式提交给后台
    		提交数据只能采用url字符串方式提交给后台,数据是不安全的
    		axios插件可以用params属性携带url拼接参数
    		
    	ii)数据包参数:
    		除get请求外的所有请求都拥有的提交数据的方式
    		该方式会将数据进行加密,打包成数据包方式提交给后台
    		打包加密数据有三种方式:urlencoded(form默认的方式)、form-data(可以提交文件)、json(提交json数据)
    		axios插件可以用data属性携带数据包参数
    		
    """
    
    """
    注意项:
    1)this.$axios({}).then(response => {}).catch(error => {}) 中的then和catch回调函数,不能写function,因为实际vue项目开发,一定会在回调逻辑用到this语法(代表vue对象),而在function中使用了this语法,function就不是普通函数了(可以理解为类,this就不能代表vue对象了)
    
    2)原生django没有提供所有类型的数据包数据解析规则,但是数据会在request.body中,可以自己解析;Django-rest-framework框架是提供了三种类型的数据包参数解析
    """
    
    

    element-ui插件

    """
    element-ui就类似于BootStrap框架,前者是在vue项目中运用,后者是在原生项目中运用,当然也可以在vue项目中运用
    
    环境搭建:
    1)安装:在前端项目根目录下的终端
    cnpm install element-ui
    
    2)配置:main.js
    import ElementUI from 'element-ui'
    Vue.use(ElementUI);
    import 'element-ui/lib/theme-chalk/index.css';
    
    3)使用:根据视频和官方API接口
    """
    
    

    jq+bs插件

    """
    一、jq环境搭建:
    1)安装:在前端项目根目录下的终端
    cnpm install jquery
    
    2)配置:自己在项目根目录下新建 vue.config.js
    const webpack = require("webpack");
    module.exports = {
        configureWebpack: {
            plugins: [
                new webpack.ProvidePlugin({
                    $: "jquery",
                    jQuery: "jquery",
                    "window.$": "jquery",
                    "window.jQuery": "jquery",
                    Popper: ["popper.js", "default"]
                })
            ]
     	}
    };
    
    二、bs环境搭建:
    1)安装:在前端项目根目录下的终端
    cnpm install bootstrap@3
    
    2)配置:自己在项目根目录下新建 vue.config.js
    import BootStrap from "bootstrap"
    import "bootstrap/dist/css/bootstrap.css"
    Vue.use(BootStrap)
    """
    
    

    Django国际化配置

    """
    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = False
    """
    
    

    小结

    """
    1)vuex
    	仓库,拥有组件间传参
    	前台存储数据的位置:cookie、localStorage、sessionStorage、vuex
    
    2)axios
    	配置:安装 => 配置给Vue.prototype.$axios
    	使用:this.$axios({}).then(response => {}).catch(error => {})
    	两种请求:form(页面跳转,前后台不分离) | ajax(只刷新数据,所有类型项目都可以)
    	前后台分离项目工作流程:前台启动提供页面 => 后台启动提供数据 => 前台渲染页面并请求后台数据
    	请求方式:get、post、patch、put、delete...
    	请求数据:
    		url拼接数据:所有请求都可以携带
    		数据包数据:只有get不能携带
    	数据包三种格式:urlencoded、form-data、json	
    
    3)element-ui
    	提供一堆布局
    
    4)jq+bs
    	提供一堆布局
    	
    
    """
    
    
  • 相关阅读:
    破解登录手机验证码思路
    自媒体平台越来越多,取舍之后我只推荐这7家平台
    微信小程序:JS 交互逻辑
    微信小程序:WXSS 样式
    微信小程序:WXML 模板
    微信小程序:页面配置 page.json
    SQLServer创建维护计划失败 错误c001f011
    远程连接提示要求的函数不受支持如何解决
    安装 SQLManagementStudio_x86_CHS(SQL Server Management Studio) 老提示重启的解决办法
    数据库属性
  • 原文地址:https://www.cnblogs.com/WQ577098649/p/12633725.html
Copyright © 2020-2023  润新知