vue

一、Vue框架

1.1 vue:可以独立完成前后端分离式web项目的JavaScript框架

# 前端三大框架   Angular React Vue
# 设计模式:MVVM
# js渐进式框架:一个页面小到一个变量,大到整个页面,均可以有vue控制,vue也可以控制整个项目

# 可以完全脱离服务器端,以前端代码复用的方式渲染整个页面:组件化开发

1.2 Vue实例

1. el: 实例
2. data: 数据
3. methons:方法
4. computed:计算
5. watch:监听
6. delimiters:分隔符

二、Vue的优点

1. 单页面, 高效
2. 数据双向绑定:
3. 虚拟DOM:页面缓存
4. 组件化开发
5. 数据驱动,从数据出发,不是从DOM出发
6. 轻量级

三、vue的指令

3.1 文本指令(v-text=、v-html=、v-once=)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>文本指令</title>
</head>
<body>
    <div id="app">
        <!-- 1. 插值表达式:在文本内置直接写变量挥着变量表达式-->
        <p>{{ msg }}</p>
        <p>{{ num * 3 - 5 }}</p>

        <!--2. v-text, v-html, v-once 三个文本指令-->
        <p v-text="message"></p>
        <h4 v-text="msg">==================</h4>
        <!-- 默认 v-text 是没有闪烁问题的 -->
        <!-- v-text会覆盖元素中原本的内容,但是 插值表达式  只会替换自己的这个占位符,不会把 整个元素的内容清空 --

        <!--v-html可以直接解析文本内容,文本内容需要一字符串形式包裹,如果文本内容为无法解析的内容,直接显示字符串-->
        <p v-html="'htmlMSG'"></p>
        <p v-html="'<b>v-html解析标签</b>'"></p>
        <p v-html="htmlMSG" @click="ChangeMSG"></p>

        <!--3. v-once:插值表达式渲染文本,once来限制文本不可修改-->
        <!--插值表达式中一个变量被限制,整个结果都被限制-->
        <p v-once="htmlMSG">{{ htmlMSG + msg }}</p>

    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'p标签的msg',
            num: 10,
            message: 'v-text文本指令',
            htmlMSG: '<b>加粗的v-html文本指令</b>'
        },
        methods: {
            ChangeMSG () {
                this.htmlMSG = '测试能否更改'
            }
        }
    })
</script>
</html>

3.2 斗篷指令(v-cloak)

<style type="text/css">
    [v-cloak] { display: none; }
</style>
<div id="app" v-cloak>
    {{ msg }}
</div>
<script src="js/vue.min.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            msg: "message"
        }
    })
</script>
<!-- 避免页面闪烁-->

3.3 属性指令(v-bind:、:)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>属性指令</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: orange;
        }
        .wrap {
            width: 100px;
            height: 100px;
            background-color: red;
        }
        .kiss {
            width: 150px;
            height: 150px;
            background-color: cyan;
        }
        .x {
            width: 300px;
        }
        .y {
            height: 300px;
        }
        .z {
            background-color: brown;
        }
    </style>
</head>
<body>
    <div id="app">
        <!--v-bind:属性名="属性值", v-bind:可以简写为:-->
        <!-- v-bind:style="MyStyle",  v-bind:class="MyClass", v-bind:aaa="MyAAA"   -->
        <div class="box" v-bind:style="myStyle" @click="changeColor('pink')"></div>

        <!-- 1. 操作单个样式: w变量的值就是为属性宽提供数据的-->
        <div class="box" v-bind:style="{'width': w}" @click="changeWidth"></div>

        <!-- 2. 操作多个样式: more_style是一个对象变量, 可以复制多个key:value的模式 -->
        <div class="box" v-bind:style="more_style" @click="changeStyle"></div>

        <!-- 3. v-bind:可以简写为: 可以绑定所有系统和自定义属性,属性一旦绑定, 后方就是变量名 -->
        <div :aaa="AAA">简写v-bind</div>

        <!-- 4. 操作单个类名 -->
        <!-- 直接赋值, c1就是变量, 变量值就是类名-->
        <div :class="c1" @click="changeClass"></div>
        <!-- 布尔切换:该div有一个kiss类名, kiss_able的true或false决定kiss的生效 -->
        <div :class="{kiss: kiss_able}"></div>

        <!-- 5. 操作多个类名:[变量1, 变量2, ... ,变量n], 每个变量的值都是的类名 -->
        <div class="[x, y, {z: is_z}]"></div>

    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            myStyle: 'background-color: red;',
            w: '400px',
            more_style: {
                width: '100px',
                height: '100px',
                borderRadius: '50%',
                backgroundColor: 'cyan'
            },
            c1: 'wrap',
            kiss_able: true,
            x: 'x',
            y: 'y',
            is_z: true,
        },
        methods: {
            changeColor (color) {
                this.myStyle = 'background-color:' + color + ';';
            },
            changeWidth () {
                this.w = '500px'
            },
            changeStyle () {

                // 可以更改全局样式
                // this.more_style = {
                //     width: '200px',
                //     height: '200px',
                //     borderRadius: '50%',
                //     backgroundColor: 'tan'
                // };

                // 也可以更改其中一个样式
                this.more_style.borderRadius = '30%';
            },
            changeClass () {
                if (this.c1 === 'box') {
                    this.c1 = 'wrap'
                } else {
                    this.c1 = 'box';
                }
            },

        },
    })

</script>
</html>

3.4 事件指令(v-on:click=、@click=)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>事件指令</title>
</head>
<body>
    <!--事件指令:1)明确事件名  2)明确事件函数  v-on:事件名="事件函数"-->


    <div id="app">
        <!-- 1. 基础的绑定事件 单击: v-on:click   双击: v-on:dblclick-->
        <p v-on:click="clickAction">单击</p>
        <p v-on:dblclick="dblclickAction">双击</p>

        <!--2. 点击事件传参数-->
        <ul>
            <li v-on:click="liAction(0)">111</li>
            <li v-on:click="liAction(1)">222</li>
            <li v-on:click="liAction(2)">333</li>
        </ul>

        <!--3. 传递事件对象-->
        <p v-on:click="sysAction1">不传自定义参数</p>
        <p v-on:click="sysAction2(888, $event)">传自定义参数</p>


        <!--4. v-on: 可以简写为 @-->
        <p @click="clickAction">单击</p>

    </div>

</body>
<script src="js/vue.js"></script>
<script>
    new Vue ({
        el: '#app',
        data:{},
        methods: {
            clickAction () {
                alert('单击')
            },
            dblclickAction () {
                alert('双击')
            },
            liAction(index) {
                alert(index)
            },
            sysAction1 (ev) {   // 接收到鼠标点击事件
                console.log(ev)
            },
            sysAction2(num, ev) {
                console.log(num);
                console.log(ev);
            },
        }
    })
</script>
</html>

3.5 表单指令(v-model=)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>表单指令</title>
</head>
<body>
    <div id="app">
        <!-- v-model表单指令,   v-model="变量" 变量给value属性提供值-->

        <!-- 1. 数据的双向绑定 将两个input框的值设定为一样即可 -->
        <input type="text" v-model="val">
        <input type="text" v-model="val">
        <p>{{ val }}</p>

        <!-- 2. 普通输入框,直接绑定变量即可-->
        <form action="">
            <input type="text" v-model="val">
        </form>

        <!-- 3. 单选框-->
        <!-- radio_val的值是多个单选框中一个value值, 代表该单选框默认选中 -->
        <form action="">
            <p>
                <label for="male"></label>
                <input type="radio" id="male" value="male" v-model="radio_val" name="sex">
                <label for="male"></label>
                <input type="radio" id="female" value="female" v-model="radio_val" name="sex">
                <button @click="alterValue">单选框提交给后台的value</button>
                <span>{{ radio_val + '被选中'}}</span>
            </p>
        </form>

        <!-- 4. 独立使用的复选框 -->
        <!-- sure_val的值为true或者false, 决定该单个复选框是否选中 -->
        <form action="">
            <p>
                <input type="checkbox" name="sure" value="同意" v-model="sure_val">
                <span>{{ sure_val }}</span>
            </p>
        </form>

        <form action="">
            <p>
                男:<input type="checkbox" name="hobby" value="male" v-model="hobby_val">
                女:<input type="checkbox" name="hobby" value="female" v-model="hobby_val">
                哇塞:<input type="checkbox" name="hobby" value="?" v-model="hobby_val">
                <span>{{ hobby_val }}</span>
            </p>
        </form>
    </div>

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

    new Vue({
        el: '#app',
        data: {
            val: '',
            radio_val: 'male',
            sure_val: true,
            hobby_val: []
        },
        methods: {
            alterValue () {
                alert(this.radio_val)
            }
        }
    })

</script>
</html>

3.6 条件指令(v-if=、v-else-if=、v-else、v-show=)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>条件指令</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
        }
        .b1 {background-color: orange;}
        .b2 {background-color: cyan;}

        .r {background-color: red;}
        .g {background-color: green;}
        .b {background-color: blue;}
    </style>
</head>
<body>
    <div id="app">
        <!-- v-if  v-show 条件指令: v-if="变量"   v-show="变量"-->

        <!-- 1. v-if、 v-show比较, 两者绑定的变量值都是true|false -->
        <!--v-if在隐藏时,不被渲染 | v-show在隐藏时,采用display: none存在-->
        <p>
            <button @click="toggleAction(true)">显示</button>
            <button @click="toggleAction(false)">隐藏</button>
        </p>
        <div class="box b1" v-if="is_show"></div>
        <div class="box b2" v-show="is_show"></div>

        <!-- 2. v-if, v-else-if v-else -->
        <p>
            <button @click="toggleShow('red')"></button>
            <button @click="toggleShow('green')">绿</button>
            <button @click="toggleShow('blue')"></button>
        </p>
        <div class="box r" v-if="color == 'red'"></div>
        <div class="box g" v-else-if="color == 'green'"></div>
        <div class="box b" v-else></div>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            is_show: false,
            color: 'red'
        },
        methods: {
            toggleAction (is_show) {
                this.is_show = is_show
            },
            toggleShow (color) {
                this.color = color
            }
        }
    })
</script>
</html>

3.7 循环指令

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>循环指令</title>
</head>
<body>
<div id="app">

    <!-- 1. 对数组的循环 -->
    <ul>
        <li v-for="(arr, i) in array">{{ i }} : {{ arr }}</li>
    </ul>

    <!-- 2. 对对象(字典)的循环 -->
    <ul>
        <li v-for="(v, k, index) in dic">{{index}}:{{k}}:{{v}}</li>
    </ul>
    <!-- 3. 列表套字典循环 -->
    <ul>
        <p v-for="info in msg">
            <span v-for="(v, k, i) in info">
                    <!--{{ person['name'] }}-->
                    <!--{{ person.age }}-->
                    <!--{{ person.gender }}-->
                    <b v-if="i != 0">|</b>
                    <span>{{ k }}:{{ v }} </span>
            </span>
        </p>
    </ul>
</div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
           array: ['aaa','bbb','ccc'],
            dic: {
               'name': 'wangyong',
                'age': 20,
                'gender': 'male',
            },
            msg: [
                {'name': 'wangyong',
                'age': 20,
                'gender': 'male',},
                {'name': 'jiyuzhi',
                'age': 20,
                'gender': 'male',},
            ]
        },
    })
</script>
</html>

3.8 todolist案例

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>todolist</title>
</head>
<body>
<div id="app">
    <div>
        <input type="text" v-model="msg_val">
        <button @click="sendMsg">提交</button>
        <ul>
            <li v-for="(msg, index) in msgs">
                <span @click="deleteMsg(index)">{{ msg }}</span>
            </li>
        </ul>
    </div>
</div>

</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg_val: '',
            // msgs: ['第一条留言', '第二条留言']
            msgs: localStorage.msgs ? localStorage.msgs.split(','):[]
        },
        methods: {
            sendMsg () {
                // 1)判断是否有数据,如果没有,直接结束
                if (!this.msg_val) return;
                // 2)将用户提交的数据添加到留言组中
                // this.msgs.push(this.msg_val);   // 尾增
                this.msgs.unshift(this.msg_val);   // 首增
                // 3)数据同步到前台数据库
                localStorage.msgs = this.msgs;
                // 4)清空输入框
                this.msg_val = '';
            },
            deleteMsg (index) {
                // splice方法删除数据
                this.msgs.splice(index, 1);
                // 同步删除数据库中的内容
                localStorage.msgs = this.msgs
            },
        }
    })
</script>
</html>

3.9 插值表达式符号修改(delimiters)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
        <p>{{ msg }}</p>
        <p>{{{ msg }}}</p>

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

    new Vue({
        el: '#app',
        data: {
            msg: 'hello world'
        },
        delimiters: ['{{{', '}}}'] // 设计修改后的样式
    })
</script>
</html>

四、vue的属性

4.1 计算属性(computed)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>监听多个变量</title>
</head>
<body>
<div id="app">
    <input type="text" v-model="a_val">
    <input type="text" v-model="b_val">
    <input type="text" v-model="c_val">
    <p>{{ val_fn }}</p>
</div>

</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            a_val: '',
            b_val: '',
            c_val: '',
        },
        // computed内部书写方法 - 管理可以监听多个变量的方法
        // 1)方法名 可以直接作为变量被渲染,值为方法的返回值
        // 2) 在方法名被渲染后(在页面中使用了),方法内部的所有变量都会被监听
        // 3)computed用来解决一个变量值依赖一个或多个变量值
        computed: {
            val_fn () {
                return this.a_val + this.b_val + this.c_val
            }
        }
    })
</script>
</html>

4.2 监听属性(watch)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>监听属性</title>
</head>
<body>
<div id="app">
    <p>姓名:<input type="text" v-model="full_name"></p>
    姓:<input type="text" v-model="last_name">
    名:<input type="text" v-model="first_name">

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

    new Vue({
        el: '#app',
        data: {
            full_name: '',
            last_name: '',
            first_name: '',
        },
        // watch内部书写方法 - 管理 监听绑定的属性(提前要存在) 的方法
        // 1)方法名 被监听的变量名(属性)
        // 2) 在方法名被渲染后,方法名代表的属性值改变,绑定的方法就会被调用
        // 3)watch用来解决多个变量值依赖一个变量值
        watch: {
            full_name () {
                let name = this.full_name.split(' ');
                this.last_name = name[0];
                this.first_name = name[1];
            }
        }
    })
</script>
</html>

五、vue的组件

5.1 组件的引入

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
    <h1 id="app">
        {{ msg }}
    </h1>
    <div id="main">
        {{ msg }}
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    // 1、new Vue创建的是vue实例,一个实例就是一个vue组件,new出了的实例称之为根组件
    // 注:在实际开发中一个页面只有一个根组件
    // 2、每个组件均由 html模板 css样式 js逻辑 组成
    //      html模板: template,根组件的模板就采用挂载点即可,无需创建自身template
    //      注:挂载点是必须的(作为虚拟DOM渲染替换的依据),挂载点可以读取,作为根组件的模板,使用根组件无需书写template
    // 3、根组件内部可以注册使用n个子组件,子组件必须拥有自己的 html模板 css样式 js逻辑
    //      如果创建子组件 | 如何使用子组件 | 父子组件间的通信
    let app = new Vue({
        el: '#app',
        data: {
            msg: 'app的msg',
            c: 'red'
        },
        // template: '<ul>{{ msg }}</ul>',
        template: `<h1 id="app" :style="{color: c}" @click="action">
{{ msg }}
</h1>
`,
        methods: {
            action () {
                alert(this.msg)
            }
        }
    });
    let main = new Vue({
        el: '#main',
        data: {
            msg: 'main的msg'
        }
    });
    // 知识点:利用原生js完成两个组件的交互
    // 获取组件的数据
    // console.log(app.msg);
    // 修改组件的数据
    // app.msg = '12345';
    main.msg = app.msg;

</script>
</html>

5.2 常用方法

5.2.1 局部组件

1. 书写自己的html代码:template:` ... `

2. 获取父组件的数据: props = []

3. 子组件数据获取时通过函数返回值来 
data () {
    return {
        num: 0
    }
}

5.2.2 根组件

1. 注册子组件函数: components:{}

2. 注册时候,如果变量名与变量值都是一样的话,可以简写一个,
    components: {
            box,
        },

5.3 父组件传递数据给子组件

# 父组件传递数据给子组件的真谛:通过绑定属性的方式进行数据传递
1. 父组件模板中写子组件标签
2. 父组件的数据绑定给子组件标签的自定义属性
3. 在子组件内部通过props拿到自定义属性
4. 使用自定义属性就可以获得父组件的数据
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
    <style>
        .box {
            width: 200px;
            border: 1px solid black;
            border-radius: 10px;
            overflow: hidden;
            float: left;
        }
        .box img {
            width: 100%;
        }
        p {
            text-align: center;
            color: red;
        }
    </style>
</head>
<body>
<div id="app">
    <!-- box_data为自己创建的数据,后期可以为后台传过来的数据 -->
    <!-- 通过在子组件中创立一个属性得到可以获取的属性值,在子组件中接受属性值,这样父组件就能将数据传给子组件看了-->
    <box v-for="data_obj in box_data" :data_obj="data_obj"></box>
</div>
</body>
<script src="js/vue.js"></script>
<script>
    let data = [
        {
            img_url: 'img/001.jpg',
            img_title: '第一张图'
        },
        {
            img_url: 'img/002.jpg',
            img_title: '第二张图'
        },
    ];

    let box = {
        // 通过props
        props: ['data_obj'],
        template:`<div class="box">
                        <img :src="data_obj.img_url" alt="" >
                        <p @click="action">第{{ num }}次点击</p>
                   </div>`,
        data () {
             return {
                 num: 0,
             }
        },
        methods: {
            action () {

                this.num++
            },
        }
    };
    new Vue({
        el: '#app',
        components: {
            box,
        },
        data: {
            box_data: data
        }
    })
</script>
</html>

5.4 子组件传递数据给父组件

# 子组件传递数据给父组件的真谛:通过发送事件请求的方式进行数据传递
1. 在根标签的挂在点对应的标签内,创建自定义标签并绑定自定义事件 @事件名="事件值"
2. "事件值"为在根组件中的事件名
3. 子组件创立需要通过方式  Vue.component('自定义标签名',{ ... })
4. 在子组件中通过事件,通过this.$emit('事件名',子组件传出的值1,子组件传出的值2,...)
5. 在根组件定义的事件中, 子组件传出的值为 创建的事件的参数,即 2 中的事件值对应的事件名的参数
<div id="app">
    <global-tag @send_action='receiveAction'></global-tag>
</div>
<script type="text/javascript">
    Vue.component('global-tag', {
        data () {
            return {
                sub_data1: "数据1",
                sub_data2: '数据2'
            }
        },
        template: '<div @click="clickAction">发生</div>',
        methods: {
            clickAction () {
                this.$emit('send_action', this.sub_data1, this.sub_data2)
            }
        }
    })
    new Vue({
        el: '#app',
        methods: {
            receiveAction (v1, v2) {
                console.log(v1, v2)
            }
        }
    })
</script>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
    <div id="app">
        <h1>{{ title }}</h1>
        <sub-tag @send_val="recv_val"></sub-tag>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    let subTag = {
        template: `
        <div>
            <input type="text" v-model="val">
            <button @click="changeTitle">修改</button>
        </div>
        `,
        data () {
            return {
                val: ''
            }
        },
        methods: {
            changeTitle () {
                if (!this.val) return;

                // 如果有数据,将数据发生给父组件
                this.$emit('send_val', this.val);

                this.val = '';
            }
        }

    };

    new Vue({
        el: '#app',
        data: {
            title: '父组件标题'
        },
        components: {
            subTag
        },
        methods: {
            recv_val (val) {
                this.title = val;
            }
        }
    })
</script>
</html>

六、生命周期钩子

表示一个vue实例从创建到销毁的这个过程,将这个过程的一些时间节点赋予了对应的钩子函数

钩子函数: 满足特点条件被回调的方法

 

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <tag></tag>

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

    let tag = {
        template: `
        <h1 @click="action">{{ msg }}</h1>
        `,
        data () {
            return {
                msg: '局部组件'
            }
        },
        methods: {
            action () {
                console.log(this.msg)
            }
        },
        beforeCreate () {
            console.log(this.data);    // undefined
            console.log('实例刚刚创建, data, methods尚未创建')
        },
        created () {
            console.log(this.msg);   // 局部组件
            // 获取方法  想要获取data, methods,需要使用 this.$options.data, this.$option.methods
            console.log(this.$options.methods);
            console.log('实例创建成功, data, methods已拥有')
        },
        mounted () {
            console.log('页面已经被渲染, data, methods已更新')
        }

    };

    new Vue ({
        el: '#app',
        data: {
            info: 123
        },
        components: {
            tag,
        },
    })

</script>
</html>

七、Vue-CLI项目搭建

7.1 环境搭建

7.1.1 安装node

官网下载node.js安装包,傻瓜式安装:http://nodejs.cn/,安装完之后就有npm,类似python中的pip

然后cmd中运行
npm install -g cnpm -- registry=https://registry.npm.taobao.org

# 如果上面不成功,则
npm install -g cnpm

7.1.2 安装脚手架

cnpm install -g @vue/cli

7.1.3 清空缓存处理

npm cache clean --force

7.2 项目的创建

7.2.1 创建项目

vue create 项目名
// 要提前进入目标目录(项目应该创建在哪个目录下)
// 选择自定义方式创建项目,选取Router, Vuex插件

 

 

7.2.2 项目启动

方式一:(不常用)

cd  vue_proj
cnpm run serve

方式二:pycharm启动

7.2.3 项目配置

7.3 项目目录 

node_modules:             # 项目依赖

public:                     # 公用文件
    favicon.ico:         # 页面标签图标
    index.html:             # 项目的唯一页面(单页面)  模板
    
src:                       # 项目开发文件目录
    assets:                   # 静态资源
        css|js|img
    components:             # 小组件
        *.vue
    views:                # 视图组件
        *.vue
    App.vue:            # 根组件
    main.js:            # 主脚本文件
router
    index.js:            # 路由脚本文件 - vue-router
store    
    index.js:            # 仓库脚本文件 - vuex
    
*.xml|json|js:            # 一系列配置文件
README.md:                # 使用说明




【记住】
根组件写在src目录下的App.vue中, 渲染的模板不是放在public目下的index.html中

若代码无高亮显示:

7.4 具体的书写位置

7.4.1 publish文件夹下的 index.html 中 写挂载点的位置

<div id="#app"></div>   

7.4.2 src文件夹下的 App.vue 写根组件

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>

7.4.3 src文件夹下的 main.js 写根组件渲染的模板

import Vue from 'vue'  // node_modules下的依赖直接写名字
import App from './App.vue'  // ./代表相对路径的当前目录,文件后缀军可以省略
import router from '@/router.js'  // @ 代表src的绝对路径
import store from './store'
// 在main中配置的信息就是给整个项目配置
// 已配置 vue | 根组件App | 路由 | 仓库
// 以后还可以配置 cookie | ajax(axios) | element-ui

Vue.config.productionTip = false;  // Tip小提示

// 原内容为, 可以由后面的new Vue替换
// new Vue({
//  router,
// store,
//  render: h => h(App)
// }).$mount('#app')

new Vue({
    el: '#app',
    router: router,
    store,
    // render: function (fn) {
    //     return fn(App)
    // }
    // 解释:function (h) {return 1} | (h) => {return 1} | h => 1
    render: readTemplateFn => readTemplateFn(App)
});

7.4.4 自定义组件

<!-- components/ClickComponents.vue -->

<!--html代码:有且只有一个根标签-->
<template>
    <div @click="actionColor" :class="{active: is_active}">点我变颜色</div>
</template>

<!--js代码:在export default {} 的括号内完成组件的各项成员:data|methods|... -->
<script>
    export default {
        name: "ClickComponents",
        data () {
            return{
                is_active: false
            }
        },
        methods: {
            actionColor () {
                this.is_active = !this.is_active;
            }
        }
    }
</script>

<!--css代码:scoped样式组件化 - 样式只在该组件内部起作用 -->
<style scoped>
    .active {
        color: red;
    }
</style>

八、路由

8.1 name使用

8.1.1 路由配置

import Main from './views/Main'
routes: [
    {
        path: '/main',
        name: 'main',
        component: Main
    }
]

8.1.2 视图使用

<router-link :to="{name: 'main'}">主页</router-link>

8.2 router-link与系统a标签的区别

router-link:会被vue渲染成a标签,但是点击这样的a标签不能发生页面的转跳,只会出现组件的替换
a:也可以完成同样的效果,但是会发生页面的转跳

8.3 路由重定向

router [
    {
        path: '/',
        name: 'home',
        component: Home
    },
    {
        path: '/home',
        redirect: '/',      // 重定向
    }
]

8.4 路由传参

8.4.1 路由传参方式一

router.js

{
    // path如果通过头直接访问,路由必须完全对应
    // :id代表可以完成任意内容匹配,用变量id保存 
    // 请求/course/detail/1 和 /course/detail/abc,id变量分别存的1和abc,
    path: '/course/detail/:id',
    name: 'course-detail',
    component: CourseDetail
},
页面跳转:Course.vue
<template>
    <div class="course">
        <h1>课程</h1>
        <hr>
        <ul>
            <li  v-for="course in courses" :key="course.title">
                <!--<router-link :to="{name: 'course-detail'}">{{ course.title}}</router-link>-->
                <router-link :to="'/course/detail/' + course.id">{{ course.title}}</router-link>
            </li>
        </ul>
    </div>
</template>

<script>
    let course_list = [
        {
            id: 1,
            title: '水浒传'
        },
        {
            id: 2,
            title: '西游记'
        },
        {
            id: 3,
            title: '三国演义'
        },
    ];
    export default {
        name: "Course",
        data () {
            return {
                courses: []
            }
        },
        // 组件创建成功去获取数据
        created () {
            this.courses = course_list
        }
    }
</script>

<style scoped>
    li a {
        display: block;
    }
    li {
        border: 1px solid orange;
        background-color: rgba(123,80,66, 0.3);
        margin-top: 10px;
        line-height: 80px;
        cursor: pointer;
    }
</style>
渲染页面:CourseDetail
<template>
    <div class="course-detail">
        <h1>课程详情</h1>
        <hr>
        <h2>{{ ctx }}</h2>
    </div>
</template>

<script>
    let course_detail_list = [
        '数据有误', '水浒传', '西游记', '三国演义'
    ];

    export default {
        name: "CourseDetail",
        data () {
            return {
                ctx: ''
            }
        },
        created () {
            console.log('详情页面被渲染了');
            // this.$route:负责路由的数据
            // this.$router:负责路由的路径
            // this.$route.params可以拿到链接中 :变量 变量中的数据
            let index = this.$route.params.id;   // 获取id的值
            if (index < 0 || index >= course_detail_list.length) index = 0;
            this.ctx = course_detail_list[index]
        }
    }
</script>

<style scoped></style>

8.4.2 路由传参方式二

router.js
{
    path: '/course/detail',
    name: 'course-detail',
    component: CourseDetail
}
页面跳转:Course.vue
<router-link :to="'/course/detail?id=' + course.id">{{ course.title }}</router-link>
渲染页面:CourseDetail.vue
created () {
    let index = this.$route.query.id;
    if (index < 0 || index >= course_detail_list.length) index = 0;
    this.ctx = course_detail_list[index]
}

8.4.3 路由传参方式三

router.js
{
    path: '/course/detail',
    name: 'course-detail',
    component: CourseDetail
}
页面跳转:Course.vue
// methods: {
//    转跳的方法 (参数) {
//        this.$router.push({
//            name: 'course-detail',
//            params 或者 query: {
//              参数们
//            },
//            : {
//                参数们
//            }
//        })
//    }
// }


methods: {
            toDetail (id) {
                this.$router.push({path: '/course/detail?id=' + id});
                this.$router.push({
                    name: 'course-detail',
                    // query: {
                    //     id:id
                    // },
                    params: {
                        id:id
                    }
                });
            }
        }
渲染页面:CourseDetail.vue
// created () {
//     let 参数的数据 = this.$route.query.参数的key 或者 this.$route.params.参数的key
// }


created () {
    let index = this.$route.params.id;
    if (index < 0 || index >= course_datail_list.length) index = 0;
    this.ctx = course_datail_list[index];


    // let index = this.$route.query.id;
    // if (index < 0 || index >= course_datail_list.length) index = 0;
    // this.ctx = course_datail_list[index];
}

8.4.4 go

this.$router.go(-1)  //返回历史记录的前一页

九、仓库(vuex)(子组件渲染父组件为例)

9.1 仓库配置 (store.js)

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
    // 全局可以访问的变量 - 获取值
    // 组件内:this.$store.state.title
    state: {
        title: '主页'
    },
    // 全局可以访问的方法 - 修改值
    // 组件内:this.$store.commit('updateTitle', '新值')
    mutations: {
        updateTitle (state, newValue) {
            state.title = newValue
        }
    },
    actions: {}
})

9.2 渲染代码

<template>
    <div class="mainsubsub">
        <input type="text" v-model="val">
        <button @click="btnClick">修改</button>
    </div>
</template>

<script>
    export default {
        name: "MainSubSub",
        data () {
            return {
                val: ''
            }
        },
        methods: {
            btnClick () {
                this.$store.commit('updateTitle', this.val)
            }
        }
    }
</script>

<style scoped>
</style>

十、前后台交互(axios, ajax)

10.1 axios

10.1.1 安装axios

>: cd 项目目录
>: cnpm install axios --save

10.1.2 配置 (main.js)

import Axios from 'axios'
Vue.prototype.$axios = Axios;

10.1.3 前台测试axios是否配置成功

// 测试axios是否配置成功, 可以在Home组件中或者其他位置
created () {
    console.log(this.$axios)
}

10.1.4 axios请求数据

10.1.4.1 get

// 方式一
this.$axios({
    url: 'http://localhost:8000/test/',
    method: 'get',
    params: {
        username: 'wangyong',
        password: '123',
        method: 'get',
    }
}).then((response) => {
    console.log(response)
}).error((error) => {
    console.log(error)
});

// 方式二 
this.$axios.get('http://localhost:8000/test/', {
    params: {
        username: 'wangyong',
        password: '123',
        method: 'get',
    }
}).then((response) => {
    console.log(response)
}).error((error) => {
    console.log(error)
});

10.1.4.2 post

// 方式一
this.$axios({
    url: 'http://localhost:8000/test/',
    method: 'post',
    data: {
        username: 'wangyong',
        password: '123',
        method: 'post',
    }
}).then((response) => {
    console.log(response)
});

// 方式二
this.$axios.post('http://localhost:8000/test/', {
    username: 'wangyong',
    password: '123',
    method: 'get',
}).then((response) => {
    console.log(response)
});

// 【注意】:post请求,在后台收到的信息在request.body中获得,从request.POST中无法获取数据

10.2 ajax

10.2.1 安装

cnpm install jquery

10.2.2 配置

10.2.2.1 新建文件vue.config.js

const webpack = require("webpack");

module.exports = {
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "window.jQuery": "jquery",
                "window.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    }
};

10.2.2.2 main.js配置

// 引入jQuery
import $ from 'jquery'
Vue.prototype.$ = $;

10.2.3 使用

window.$.ajax({
    url:"",
    type:"get"
}).then(response => {
    console.log(response);    
});


window.$.ajax({
    url:"",
    type:"post",
    data:data,
}).then(response => {
    console.log(response);    
});

10.3 django解决跨域问题(Access-Control-Allow-Origin => CORS)

10.3.1 什么是跨域

通常情况下,A网页访问B服务器资源时,不满足以下三个条件其一就是跨域访问

1)服务器不一致 - ip
2)应用不一致 - 端口
3)协议不一致 - http <-> https

10.3.2 解决跨域问题

'''
1)安装django-cors-headers模块
pip3 install django-cors-headers

2)在settings.py中配置
# 注册app
INSTALLED_APPS = [
    ...
    'corsheaders'
]
3)添加中间件
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware'
]
4)允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
'''

 

 

 

 

十一、前台操作cookie: vue-cookie

11.1 安装

>: cd 项目目录
>: cnpm install vue-cookie --save

11.2 配置(main.js)

import cookie from 'vue-cookie'
Vue.prototype.$cookie = cookie;

11.3 使用(get, post都没问题)

// 获取后台返回的token值做为cookie
let token = response.data.token;

// 设置cookie值
// this.$cookie.set(key, value, time)
this.$cookie.set('token', token, 1);

// 获取cookie
// this.$cookie.get(key)
console.log(this.$cookie.get('token'));

// 删除cookie
// this.$cookie.delete(key)
this.$cookie.delete('token');

十二、vue中使用element-ui、bootstrap、vant

12.1 element-ui页面组件框架

12.1.1 安装:前端项目目录下的终端

>: cnpm install element-ui

12.1.2 配置:main.js

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

12.2 bootstrap页面组件框架

12.2.1 安装:前端项目目录下的终端

>: cnpm install jquery
>: cnpm install bootstrap@3

12.2.2 配置jquery

12.2.2.1 新建文件vue.config.js

const webpack = require("webpack");

module.exports = {
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "window.jQuery": "jquery",
                "window.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    }
};

12.2.2.2 修改bootstrap\js(有时候不改也可以)

将bootstrap\js下的所有js文件的最后一行 (jQuery)改为 (window.Jquery)

测试时候,需要加上window

 

12.2.3 配置bootstrap:main.js

import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'

12.3 vant页面组件框

12.3.1 安装:前端项目目录下的终端

>:    cnpm i vant -S

12.3.2 引入组件:自动按需引入组件 (推荐)     (babel.config.js)

// 安装插件
cnpm i babel-plugin-import -D
module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
        ['import', {
            libraryName: 'vant',
            libraryDirectory: 'es',
            style: true
        }, 'vant']
    ]
}

12.3.3 配置vant:main.js

import 'vant/lib/index.css';

12.3.4 案例引入:List

12.3.4.1 引入:  views\list.vue

<template>
    <div>
        <h1>列表页</h1>


        <van-pull-refresh v-model="isLoading" @refresh="onRefresh">

            <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
                <van-cell v-for="item in list" :key="item" :title="item"/>
            </van-list>

        </van-pull-refresh>
    </div>
</template>

<script>
    import Vue from 'vue';
    import {List, Cell, PullRefresh, Toast } from 'vant';

    Vue.use(List);
    Vue.use(Cell);
    Vue.use(PullRefresh);
    Vue.use(Toast);
    export default {
        name: "list",
        data() {
            return {
                list: [],
                loading: false,
                finished: false,
                isLoading: false,
            }
                ;
        },
        methods: {
            onRefresh() {
                setTimeout(() => {
                    Toast('刷新成功');
                    this.isLoading = false;
                    for (let i = 0; i < 20; i++) {
                        this.list.push(this.list.length + 1);
                    }

                }, 500);
            },
            onLoad() {
                // 异步更新数据
                // setTimeout 仅做示例,真实场景中一般为 ajax 请求
                setTimeout(() => {
                    for (let i = 0; i < 20; i++) {
                        this.list.push(this.list.length + 1);
                    }

                    // 加载状态结束
                    this.loading = false;

                    // 数据全部加载完成
                    if (this.list.length >= 200) {
                        this.finished = true;
                    }
                }, 1000);
            }
        }
    }
</script>

<style scoped>

</style>

12.3.4.2 outes\index.js下配置路由

{
    path: '/list',
    name: 'LIST',
    component: LIST,
},

12.3.4.3 导入组件

<!-- 在需要引入的vue中 -->
<router-link to="/list">列表页</router-link>

 

posted on 2020-02-20 15:46  软饭攻城狮  阅读(244)  评论(1编辑  收藏  举报

导航