Vue框架的介绍及如何使用

Vue框架 定义:渐进式 JavaScript 框架 渐进式:可以控制一个页面的一个标签,可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目。

Vue框架

定义:渐进式 JavaScript 框架

渐进式:可以控制一个页面的一个标签,可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目。

通过对框架的了解与运用程度,来决定其在整个项目中的应用范围,最终可以独立以框架方式完成整个web前端项目

一、Vue基础

1、什么是Vue

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

2、为什么要学习Vue

三大主流框架之一:Angular(庞大) React(精通移动端) Vue(吸取前两者优势,轻量级)

先进的前端设计模式:MVVM

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

3、特点

有指令(分支结构,循环结构...),复用页面结构等

有实例成员(过滤器,监听),可以对渲染的数据做二次格式化

有组件(模块的复用或组合),快速搭建页面

 

单页面web应用

数据驱动

数据的双向绑定

虚拟DOM

4、Vue安装

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

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

2)本地导入
<script src="js/vue.js"></script>
"""

注意:

挂载点介绍

el: 挂载点
1)一个挂载点只能控制一个页面结构(优先匹配到的结构)
2)挂载点挂载的页面标签严格建议用id属性进行匹配(一般习惯用app)
3)html标签与body标签不能作为挂载点(html和body标签不可以被替换,组件中详细介绍)
4)是否接受vue对象,是外界是否要使用vue对象的内容决定的

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>挂载点</title>

<body>
    <div id="app">
        <div>
            {{ num }}
        </div>
        <div>
            {{ num }}
        </div>
    </div>
    <div id="main">
        {{ n }}
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            num:100
        }
    });
    console.log('12345');
    console.log(app.num);
    // console.log(app.$data.num);
    console.log(app.$el);

    new Vue({
        el: '#main',
        data:{
            n:app.num
        }
    })
</script>
</html>
挂载点el

插值表达式

1)空插值表达式:{{ }}
2)插值表达式中渲染的变量在data中可以初始化
3)插值表达式可以进行简单运算与简单逻辑
4)解决插值表达式符号冲突,用delimiters自定义(了解)

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>插值表达式</title>

</head>
<body>
    <div id="app">
        <p>{{ info }}</p>
        <p>{{ msg }}</p>
        <p>{{ }}</p>
        <p>{{ num }}</p>
        <p>{{ num + 10 * 2 }}</p>
        <p>{{ msg + num }}</p>
        <p>{{ msg.length + num }}</p>
        <p> {{ msg[4] }}</p>
        <p> {{ msg.split('') }}</p>
<!--        <p>[{ num }]</p>-->
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            info:'信息',
            msg:'message',
            num:10
        },
        // 控制vue插值表达式符号 (了解)
        // delimiters: ['[{','}]']
    })
</script>
</html>
插值表达式例子

过滤器

1)用实例成员filters来定义过滤器
2)在页面结构中,用 | 来标识使用过滤器
3)过滤方法的返回值就是过滤器过滤后的结果
4)过滤器可以对1~n个变量进行过滤,同时还可以传入辅助的变量,
过滤器方法接受参数是按照传入的位置先后

计算属性

"""
计算属性:
1)即vue中的方法属性,就是方法名可以作为属性来使用,属性值为方法的返回值
2)在computed中声明的方法属性,不能在data中重复声明,只是比data中声明的属性要多出写逻辑的地方
3)方法属性自带监听机制,在方法属性中出现的变量都会被监听,一旦有任何被监听的变量值发生更新,方法属性都会被调用,更新方法属性的值
4)方法属性一定要在页面中渲染一次,方法属性才有意义,多次渲染 方法属性只会被调用一次

应用场景:计算器,一个变量依赖于多个变量,且需要进行一定的逻辑运算

"""
<div id="app">
    <!-- type="number"表示只能写数字 -->
    <input type="number" v-model="num1">
    +
    <input type="number" v-model="num2">
    =
    <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>
姓名拆分案例

JS反引号变量占位

"""
1)双引号:
    "前缀" + 变量 + "后缀"
    
2)单引号:
    '前缀' + 变量 + '后缀'

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

基础实例成员

1)el:挂载点
2)data:提供渲染的数据
3)methods:提供绑定的方法
4)filters:提供自定义过滤器,过滤器可以同时过滤多个参数,还可以串联过滤器
5)delimiters:插值表达式标识符,['{{','}}'] 
6)computed:计算(方法属性)
7)props:属性
8)watch:监听

指令

文本指令

1)v-* 是vue指令,会被vue解析,v-text="num"中的num是变量(指令是有限的,不可以自定义)

2)v-text是原样输出渲染内容,渲染控制的标签自身内容会被替换掉(<p v-text="num">123</p>会被num替换)

3)v-html可以解析渲染html语法的内容

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>文本指令</title>

</head>
<body>
    <div id="app">
        <p>{{ num | add(300) }}</p>
        <p v-text="num" class="123"></p>
        <p v-text="num">123</p>
        <p v-text="info"></p>
        <p v-html="info"></p>

        <!-- js基本数据类型:字符串、数字、布尔、undefined -->
        <p v-text="'abc' + num + 10"></p> <!-- abc10010 -->
        <p>{{ 'abc' + num + 10 }}</p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            num:100,
            info: '<i>info内容</i>'
        },
        filters:{
            add:function (a,b) {
                return a + b;
            }
        }
    })
</script>
</html>
v-text指令

 事件指令

"""
/**
 * 一、数据驱动
 *  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>  只传入自定义参数,当然也可以传入事件对象
 */
"""

重点:v-on: 可以简写为 @
 
<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>
view.code
<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>
事件补充

斗篷指令

v-cloak:避免屏幕闪烁

1)属性选择器,会将v-cloak属性所在的标签隐藏
2)当vue环境加载后,会将v-cloak属性解析移除,所以内容{{ num }}就会显示出来
3)而现在vue已经准备完毕,所以用户会直接看到数值10,而不会看到 页面从{{ num }}闪烁成数值10 """

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
    <div id="app" v-cloak>
        <p>{{ num }}</p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            num:10
        },
    })
</script>
</html>
View Code

属性指令

属性指令
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属性(了解):
      绑定的变量:值是一个字典
重点:v-bind: 可以简写为 :
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>属性指令</title>
    <style>
        .b1 {
            width: 100px;
            height: 100px;
            background-color: red;
        }
        .b2 {
            border-radius: 50%;
        }
    </style>
</head>
<body>
    <!--1) 标签的属性没有被v-bind绑定,就是同原来一样基本使用-->
    <!--2)标签的属性被v-bind绑定,就会被vue控制,值就会变为变量-->
    <!-- 换而言之,如果一个属性要被vue控制,填写变量就要用v-bind来处理-->
    <div id="app">
        <p v-bind:class="a" style="color: red;background-color:orange " v-bind:title="t" v-bind:owen="'o'">段落</p>
        <p v-bind:class="b"></p>
        <p class="b1 b2"></p>
        <p v-bind:class="[c,d]"></p>
        <p v-bind:class="{b1:0}"></p>
        <!--
        a是变量,值就是类名
        b1就是类名,不是变量
        e是变量,值为布尔,决定b1类是否起作用
        -->
        <p v-bind:class="[a,{b1:e}]"></p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            t:'悬浮提示',
            a:'a1',
            b:'b1 b2',
            c:'b1',
            d:'b2',
            e:true,
        }
    })
</script>
</html>
<p v-bind:style="myStyle"></p>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            myStyle: {
                width: '50px',
                height: '50px',
                backgroundColor: 'pink',
                borderRadius: '50%'
            }
        },
    })
</script>

案例:

<style>
    .live{
        background-colorL:yellowgreen
    }
</style>

<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: 0,
        },
        methods: {
            changeLive (index) {
                // this就代表当前vue对象,和app变量等价
                // app.isLive = index;
                this.isLive = index;
            }
        }
    })
</script>  
View Code

表单指令

1)语法:v-model="变量"
2)v-model绑定的变量控制的是表单元素标签的value属性值
3)v-model要比v-bind:value要多一个监听机制
4)数据的双向绑定:
    v-model可以将绑定的变量值映射给表单元素的value
    v-model还可以将表单元素的新value映射给表单的变量
<!-- 两个输入框内容会同时变化 -->
<div id="app">
    <form action="" method="">
        <input name="n1" type="text" v-model="v1">
        <input name="n2" type="text" v-model="v1">
        <button type="submit">提交</button>
    </form>
</div>
<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="1">你是第一个p</p>
            <p v-else-if="2">你是第二个p</p>
            <p v-else>你是第三个p</p>
        </div>
    </div>
    <script>
        new Vue({
            el: '#app',
            data:{
                isShow:false,
            }
        })
    </script>

案例:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>案例</title>
<style>
    body {
        margin: 0
    }
    button {
        width: 60px;
        line-height: 40px;
        float: right;
    }
    .bGroup:after {
        display: block;
        content: '';
        clear: both;
    }
    .box {
        /* vw: view width  vh: view height*/
        width: 100vw;
        height: 200px;
    }
    .red {
        background-color: red;
    }
    .green {
        background-color: green;
    }
    .blue {
        background-color: blue;
    }

    button.active {
        background-color: cyan;
    }
</style>

</head>
<body>
    <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>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            isShow: 'red'
        }
    })
</script>
</html>
View Code

循环指令

"""
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>

案例:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
    .box {
        width: 280px;
        border: 1px solid #eee;
        border-radius: 5px;
        overflow: hidden; /* 隐藏超出父级显示范围外的内容 */
        text-align: center; /* 文本相关的属性大多默认值是inherit */
        float: left;
        margin: 10px;
    }
    .box img {
        width: 100%;
    }
    </style>
</head>
<body>
    <div id="app">
        <div class="box" v-for="obj in goods">
            <img :src="obj.img" alt="">
            <p>{{ obj.title }}</p>
        </div>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    let goods = [
        {
            "img":"https://***1.jpg",
            "title": "商品1"
        },
        {
            "img":"https://***2.jpg",
            "title": "商品2"
        }
    ];

    new Vue({
        el:"#app",
        data:{
            goods,
        }
    })
</script>
</html>
View Code

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);
"""

splice:

 

 

案例:留言板

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>todolist</title>
    <style>
        li:hover {
            color: red;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div id="app">
        <form action="">
            <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>
</body>
<script src="js/vue.js"></script>
<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>
</html>
View Code

 

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