一、VUE介绍

vue
以数据驱动的web渐进式框架

三大主流框架: Angular React Vue

设计模式:MVVM

1.数据驱动 => 不直接操作DOM
2.单页面web应用 => 构建的网站其实只有一个页面
3.数据的双向绑定
4.虚拟DOM

文件后缀: .vue => 组件 => Vue实例
<template></template>
<script></script>
<style></style>

组件化开发

1、VUE实例   

v-bind      挂载点
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>vue实例</title>
    <style type="text/css">
        p {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>
    <div id="app" class="app">
        <p title="你真的是P">你是P</p>
        <!-- v-bind: 属于vue语法:vue指令 -->
        <!-- 第一个title是html标签的全局属性title -->
        <!-- 第二个title是vue的一个变量,变量名可以随意自定义 -->
        <p v-bind:title="title">你就是P</p>
        <!-- vue的变量一般需要进行初始化(赋初值) -->
    </div>

    <div id="main">
        <p v-bind:title="my_title">你还是P</p>
    </div>
</body>
<!-- 在页面中引入vue -->
<script src="js/vue-2.5.17.js"></script>
<!-- 拥有vue环境后可以写vue支持的语法逻辑 -->
<script type="text/javascript">
    // 自身代码块
    // 创建vue实例
    new Vue({  
        // 将实例与页面结构进行关联, 尽量(只允许)用id进行绑定(将唯一的对象与页面唯一的结构进行一一绑定)
        // 该实例只操作关联的页面结构(包含子结构)
        // el: "#app"
        el: '.app',
        data: {
            title: "你就是P..."
        }
    });

    // 将一个vue实例挂载到页面的一个页面结构
    new Vue({
        // 挂载点
        el: "#main",
        data: {
            my_title: ""
        }
    })

</script>
</html>

2、Vue 实例data

插值表达式
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>vue实例之data</title>
</head>
<body>
    <div id="app">
        <!-- 插值表达式 -->
        {{ msg }}
        {{ num }}
        <!-- 插值表达式中可以进行运算 -->
        {{ 1 + 2 + 3 * 4 }}
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        // data: 数据
        // 为挂载点内部的vue变量提供值
        data: {
            msg: "hello world!",
            num: 88888
        }

    })
</script>
<script type="text/javascript">
    // 普通js代码块
    // 获取msg,num变量的值

    // 1.得到vue实例
    console.log(app);
    // 2.获取vue变量data: $data
    console.log(app.$data);
    // 3.获取目标变量值
    console.log(app.$data.msg);

    // 直接获取值
    console.log(app.msg);
    console.log(app.num);
</script>
</html>

3、methods

 <p v-bind:title="my_title">
 <p class="box" v-on:click="abcClick">{{ abc }}</p>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>methods</title>
    <style type="text/css">
        .box {
            background-color: orange
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- v-on: 指令,操作事件的 -->
        <p class="box" v-on:click="abcClick">{{ abc }}</p>
        <p class="box" v-on:click="defClick">{{ def }}</p>
        <p class="box" v-on:mouseover="action">88888</p>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#app',
        data: {
            abc: "12345 上山打老虎 老虎不在家 ...",
            def: "67890 呵呵"
        },
        // methods为挂载点内部提供方法的实现体
        methods: {
            abcClick: function (ev) {
                console.log(ev);
                console.log("abc is clicked");
            },
            defClick (ev) {
                console.log(ev);
                console.log("def is clicked");
            },
            action () {
                console.log("被悬浮");
            }
        }
    })
</script>
</html>

4、computed

<input type="text" name="xing" v-model="fisrt_name"></div>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>computed</title>
</head>
<body>
    <div id="app">
        <div>
            <!-- v-model vue进行数据双向绑定的指令 -->
            <label for="xing">姓:</label><input type="text" name="xing" v-model="fisrt_name">
        </div>
        <div>
            <label for="ming">名:</label><input type="text" name="ming" v-model="last_name">
        </div>
        <div>
            <!-- 通过插值表达式实现 -->
            <div>姓名: {{ fisrt_name + " " + last_name }} </div>
            <!-- 通过computed实现 -->
            <div>姓名: {{ full_name }} </div>
            <!-- 通过methods实现 -->
            <div>姓名: {{ full_name_bac() }} </div>
        </div>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            fisrt_name: "",
            last_name: "",
            // full_name: ""
        },
        // 一个变量依赖于多个变量
        // 采用computed
        computed: {
            full_name: function () {
                // full_name对fisrt_name及last_name两个变量进行监听,两个值只有有一个变化,full_name就会随之变化,并且可以实时渲染到页面
                return this.fisrt_name + " " + this.last_name;
            }
        },
        methods: {
            full_name_bac: function () {
                return this.fisrt_name + " " + this.last_name;
            }
        }
    })
</script>
</html>

5、监听 watch

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>watch</title>
</head>
<body>
    <div id="app">
        <div>
            <label>姓名:</label>
            <input type="text" v-model="full_name">
        </div>
        <p>姓: {{ first_name }} </p>
        <p>名: {{ last_name }} </p>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 多个变量依赖于一个变量, 对该变量进行监听
    new Vue({
        el: "#app",
        data: {
            full_name: "",
            first_name: "",
            last_name: ""
        },
        // 监听full_name变量,通过full_name具体修改first_name,last_name
        watch: {
            full_name () {
                var fullName = this.full_name;
                console.log(fullName);
                this.first_name = fullName.split(" ")[0];
                this.last_name = fullName.split(" ")[1];
            }
        }
    })
</script>
</html>

6、delimiters 修改插值表达式默认符号

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>delimiters</title>
</head>
<body>
    <div id="app">
        {{ msg }} ${ msg }
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#app',
        data: {
            msg: 'message'
        },
        delimiters: ['${', '}']
    })
</script>
</html>

7、生命周期钩子

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

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

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>生命周期钩子</title>
</head>
<body>
    <div id="app">
        {{ msg }}
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            msg: "message"
        },
        beforeCreate () {
            console.log("实例刚刚创建");
            console.log(this.msg);
        },
        created () {
            console.log("实例创建成功, data, methods");
            console.log(this.msg);
        }
        // 拿到需求 => 确定钩子函数 => 解决需求的逻辑代码块
    })
</script>
</html>

二、学习总结

vue简介
数据驱动的web渐进式框架

数据驱动(不直接操作DOM)
单页面应用(减少由加载页面产生的请求次数)
数据的双向绑定(数据间的实时动态渲染)
虚拟DOM
组件化开发,遵循MVVM设计模式

vue实例
实例 == 组件

el: 挂载点,一般采用id,vue控制html页面结构的连接点
--  #app

data: 数据,为页面变量提供数据的,一般变量都需要初始化
--  {{}}: 插值表达式,可以包含变量已经表达式

methods: 方法,为页面提供逻辑的实现体
--  v-on:事件

computed: 计算,一个变量依赖于多个变量
--  变量名: function () { return 变量的逻辑值 }

watch: 监听,多个变量依赖于一个变量
--  变量名: function () { 多个变量依赖于此变量的逻辑代码块 }

delimiters: 修改插值表达式默认符号, ["${", "}"]    {{}} => ${}

变量的取值
var app = new Vue({
    el: "#app",
    data: {
        msg: "message"
    }
})
app.msg
app.$data.msg


生命周期钩子
在一个vue实例从创建到销毁的整个过程中一些时间节点的回调方法


课程内容

vue的指令
什么是vue的指令
vue指令有哪些,每个指令的用途
文本类操作的指令
条件指令
循环指令
涉及绑定的指令

1、文本类操作的指令

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>文本类指令</title>
    <style type="text/css">
        p {
            line-height: 21px;
            background-color: orange
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- html全局属性语法: 全局属性名="属性值" -->
        <p v-bind:title="title" a="a" b="b">你是p</p>

        <!-- v-model也是对文本操作的指令,操作的是表单元素的value文本 -->
        <input type="text" v-model="msg">
        <!-- 采用文本指令后,页面标签的内容由vue实例控制,原来用于表示标签的文本均会被替换 -->
        <p>{{ msg }}</p>
        <!-- eg:原文本会被msg替换 -->
        <p v-text='msg'>原文本</p>
        <!-- 可以解析带html标签的文本信息 -->
        <p v-html='msg'></p>
        <!-- v-once控制的标签只能被赋值一次 -->
        <p v-once>{{ msg }}</p>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 指令: 出现在html标签中可以被vue解析处理的全局属性
    new Vue({
        el: "#app",
        data: {
            title: "",
            msg: "message"
        }
    })
</script>
</html>

2、解决页面闪烁

  <div id="app" v-cloak>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="js/vue-2.5.17.js"></script>
    <style type="text/css">
        [v-cloak] {
            /*display: none;*/
        }
    </style>
</head>
<body>

    <div id="app" v-cloak>
        {{ msg }}
    </div>
</body>
<!-- <script src="js/vue-2.5.17.js"></script> -->
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            msg: "message"
        }
    })
</script>
</html>

3、v-bind指令

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>v-bind</title>
    <style type="text/css">
        .abc {
            background-color: red
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- v-bind: -->
        <!-- 该指令 绑定 的是属性(html标签的全局属性) -->
        <!-- 绑定后的属性的属性值可以由变量控制 -->
        <p v-bind:abc="abc"></p>
        
        <!-- 绑定后 操作单一变量 -->
        <p v-bind:title="t1">p1p1p1p1p1p1p1</p>
        <!-- 绑定后 操作普通字符串 -->
        <p v-bind:title="'t2'">p2p2p2p2p2p2p2</p>

        <!-- 多类名 单一变量操作 -->
        <p v-bind:class="t3">p3p3p3p3p3p3p3</p>
        <p v-bind:class="[t4, tt4]">p4p4p4p4p4p4</p>

        <!-- 绑定class的{}语法 {key: value} key就是实际的类名,value是该类名的显隐(true就是起作用,false就是不起作用) -->
        <p v-bind:class="{abc: false}">p5p5p5p5p5p5</p>
        <p v-bind:class="{abc: t5}" v-on:click="fn">p5p5p5p5p5p5</p>

        <!-- class的[] {} 结合使用 -->
        <!-- class的值为p6 pp6, t6 tt6是值为true|false的变量,控制p6 pp6是否起作用 -->
        <p v-bind:class="[{p6: t6}, {pp6: tt6}]">p6p6p6p6p6p6p6p6</p>

        <!-- v-bind操作class -->
        <!-- [a, b] a,b为变量,对其赋值的是class的具体值 -->
        <!-- eg: a:active b:red => class="active red" -->

        <!-- {a: b} a为class值, b为值为true|false的变量,控制a的显隐 -->
        <!-- eg: b:true => class="a" -->
        <!-- eg: b:false => class="" -->

        <!-- v-bind:指令可以简写 : -->
        <p :class="'simple'">简写</p>


        <!-- 操作style -->
        <!-- style一般都是多条样式 -->
        <div :style="div_style"></div>
        <div :style="{width: '100px', height: '100px', backgroundColor: 'blue'}"></div>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el:"#app",
        data: {
            abc: "ABC",
            t1: "p1的title",
            t3: "p pp",
            t4: "p",
            tt4: "pp",
            t5: false,
            t6: true,
            tt6: true,
            div_style: {
                width: "200px",
                height: "200px",
                backgroundColor: "cyan"
            }
        },
        methods: {
            fn () {
                this.t5 = !this.t5;
            }
        }
    })
</script>
</html>

4、v-on事件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>v-on指令</title>
    <style type="text/css">
        p {
            width: 100px;
            height: 100px;
            background-color: orange
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- v-on: 指令 -->
        <!-- 简写: @ -->
        <!-- 绑定的是事件,操作的是事件对应的方法名 -->
        <p @click="fn1"></p>
        <!-- 直接绑定方法名,不会携带自定义参数,但回调时能取到事件参数ev -->
        <p @click="fn2"></p>
        <!-- 带()的方法绑定,只传自定义参数,回调时只能取到自定义参数,事件参数ev丢失 -->
        <p @click="fn3(10)"></p>
        <!-- 带()的方法绑定,传入自定义参数同时,显式传入事件$event,回调时可以取到自定义参数及事件参数ev -->
        <p @click="fn4($event, 10, 20)"></p>
        <p @click="fn5(10, $event, 20)"></p>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        methods: {
            fn1: function () {
                console.log("click event");
            },
            fn2 (ev) {
                console.log(ev);
            },
            fn3 (num) {
                console.log(num);
            },
            fn4 (ev, n1, n2) {
                console.log(ev);
                console.log(n1);
                console.log(n2);
            },
            fn5 (n1, ev, n2) {
                console.log(ev);
            }
        }
    })
</script>
</html>

5、v-mode指令

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>v-model</title>
</head>
<body>
    <div id="app">
        <form action="">
            
            <!-- 数据的双向绑定 -->
            <!-- v-model绑定的是value,所以省略 -->
            <input type="text" v-model="val1" name="usr">
            <textarea v-model="val1"></textarea>
            <p v-text="val1"></p>

            <!-- 单一复选框 -->
            <!-- val2值为true|false的变量,控制单选框是否被选中 -->
            <!--  -->
            <input type="checkbox" v-model="val2" name="ck1">
            <!-- val3值为自定义"选中"|"未选中",控制单选框是否被选中 -->
            <!-- 选中状态,提交给后台可以对应的value为on,为选中状态,不向后台提交value值 -->
            <input type="checkbox" v-model='val3' true-value="选中" false-value="未选中" name="ck2" />

            <!-- 多复选框 -->
            <!-- 多个复选框的v-model绑定一个变量 -->
            <!-- 该变量为数组数据,存放的是复选框的value值(value值必须明确) -->
            <!-- 出现在数组中的value值对应的复选框默认为选中状态 -->
            <div>
                篮球<input type="checkbox" value="lq" v-model="val4" name="ck3">
                足球<input type="checkbox" value="zq" v-model="val4" name="ck3">
                乒乓球<input type="checkbox" value="ppq" v-model="val4" name="ck3">
            </div>
            
            <!-- 多单选框 -->
            <!-- 多个单选框的v-model绑定一个变量 -->
            <!-- 变量值为多个单选框中一个的value值,则该单选框为默认选中状态 -->
            <div>
                男:<input type="radio" value="" v-model='val5' name="sex" />
                女:<input type="radio" value="" v-model='val5' name="sex" />
            </div>

            <button type="submit">提交</button>
        </form>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            val1: "",
            val2: false,
            val3: "选中",
            val4: ['lq', 'ppq'],
            val5: "",
        }
    })
</script>
</html>

6、条件渲染的指令

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>条件渲染</title>
    <script src="js/vue-2.5.17.js"></script>
    <style type="text/css">
        .box {
            width: 200px;
            height: 200px;
        }
        .r {background-color: red}
        .o {background-color: orange}
    </style>
    <style type="text/css">
        ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        .wrap, .main {
            width: 500px;
            height: 240px;
        }
        li {
            float: left;
            background-color: #666;
            margin-right: 20px;
        }
        ul:after {
            content: "";
            display: block;
            clear: both;
        }
        .red {background-color: red}
        .green {background-color: green}
        .blue {background-color: blue}
    </style>
</head>
<body>
    <div id="app">
        <button @click="toggle">显隐切换</button>
        <!-- v-if -->
        <div class="box r" v-if="isShow"></div>
        <!-- v-show -->
        <div class="box o" v-show="isShow"></div>
        <!-- 1.条件渲染的值为true|false -->
        <!-- 2.true代表标签显示方式渲染 -->
        <!-- 3.false v-if不渲染到页面,v-show以display:none渲染到页面,但也不会显示 -->

        <!-- v-if v-else-if v-else -->
        <ul>
            <li @mouseover="changeWrap(0)">red</li>
            <li @mouseover="changeWrap(1)">green</li>
            <li @mouseover="changeWrap(2)">blue</li>
        </ul>
        <!-- red页面逻辑结构 -->
        <div class="wrap red" v-if="tag == 0" key="0">...</div>
        <!-- green页面逻辑结构 -->
        <div class="wrap green" v-else-if="tag == 1" key="1">...</div>
        <!-- blue页面逻辑结构 -->
        <div class="wrap blue" v-else key="2">...</div>
        <!-- v-if相关分支操作,在未显示情况下,是不会被渲染到页面中 -->
        <!-- 通过key全局属性操作后,渲染过的分支会建立key对应的缓存,提高下一次渲染速度 -->


        <ul>
            <li @mouseover="changeMain(0)">red</li>
            <li @mouseover="changeMain(1)">green</li>
            <li @mouseover="changeMain(2)">blue</li>
        </ul>
        <!-- red页面逻辑结构 -->
        <div class="main red" v-show="whoShow(0)">...</div>
        <!-- green页面逻辑结构 -->
        <div class="main green" v-show="whoShow(1)">...</div>
        <!-- blue页面逻辑结构 -->
        <div class="main blue" v-show="whoShow(2)">...</div>

    </div>
</body>

<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            isShow: false,
            tag: 0,
            flag: 0
        },
        methods: {
            toggle () {
                this.isShow = !this.isShow;
            },
            changeWrap (num) {
                this.tag = num;
            },
            changeMain (num) {
                // this.flag num
                this.flag = num;
            },
            whoShow (num) {
                // this.flag num
                return this.flag == num;
            }
        }
    })
</script>
</html>

7、列表渲染指令

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>列表渲染</title>
</head>
<body>
    <div id="app">
        <h1>{{ msg }}</h1>
        <!-- v-for="item in items" -->
        <!-- 遍历的对象: 数组[] 对象(字典){} -->
        <ul>
            <li>{{ list[0] }}</li>
            <li>{{ list[1] }}</li>
            <li>{{ list[2] }}</li>
            <li>{{ list[3] }}</li>
            <li>{{ list[4] }}</li>
        </ul>

        <!-- n为遍历的元素值 -->
        <ul>
            <li v-for="n in list">{{ n }}</li>
        </ul>

        <!-- 一般列表渲染需要建立缓存 -->
        <!-- 列表渲染是循环,需要赋值变量给key,使用key需要v-bind:处理 -->
        <!-- v-for变量数组[]时,接收两个值时,第一个为元素值,第二个为元素索引 -->
        <ul>
            <li v-for="(n, i) in list" :key="i">value:{{ n }} | index: {{ i }}</li>
        </ul>

        <ul>
            <li>{{ dic['name'] }}</li>
            <li>{{ dic.age }}</li>
            <li>{{ dic.gender }}</li>
        </ul>
        
        <!-- v-for变量对象{}时,接收三个值时,第一个为元素值,第二个为元素键,第三个为元素索引 -->
        <ul>
            <li v-for="(v, k, i) in dic" :key="k">value:{{ v }} | key:{{ k }} | index: {{ i }}</li>
        </ul>


        <!-- 遍历的嵌套 -->
        <div v-for="(person, index) in persons" :key="index" style="height: 21px;">
            <div v-for="(v, k) in person" :key="k" style="float: left;">{{ k }} : {{ v }}&nbsp;&nbsp;&nbsp;</div>
        </div>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            msg: "列表渲染",
            list: [1, 2, 3, 4, 5],
            dic: {
                name: '小VV',
                age: 88888,
                gender: ''
            },
            persons: [
                {name: "zero", age: 8},
                {name: "egon", age: 78},
                {name: "liuXX", age: 77},
                {name: "yXX", age: 38}
            ]
        }
    })
</script>
</html>

8、todolist案列

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>todoList案例</title>
</head>
<body>
    <div id="app">
        <div>
            <input type="text" v-model="val">
            <button type="button" @click="submitMsg">提交</button>
        </div>
        <ul>
            <li v-for="(v, i) in list" :key="i" @click="removeMsg(i)">{{ v }}</li>
        </ul>
        {{ list }}
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    new Vue({
        el: "#app",
        data: {
            val: "",
            list: []
        },
        methods: {
            submitMsg () {
                // 往list中添加input框中的value
                if (this.val) {
                    this.list.push(this.val);
                    this.val = ""
                }
            },
            removeMsg(index) {
                this.list.splice(index, 1)
            }
        }
    })
</script>
</html>

三、指令总结

vue 指令

文本操作指令
v-text  <==> {{}}
v-html
v-once + {{}}

防止页面闪烁
v-cloak
[v-cloak] {
    display: none;
}

关键指令
v-bind:
操作的是全局属性,让属性可以绑定变量,简写 :
:title
:class => a(单一变量) | [a, b](两个变量) | {a: b}(b为布尔类型记得类a是否起作用) | [{a: aa}, {b: bb}]
:style => {width: "200px", height: "200px"}
:key => 通过唯一标识建立缓存

v-on:
操作的是事件,让事件可以绑定方法,绑定的方法可以不携带参数(方法名),也可以携带参数(方法名(参数)), 简写 @
@click="btnClick"
@click="btnClick(10)"
@click="btnClick($event, 10)"

v-model
操作的是表单元素value值,可以完成数据的双向绑定
text  v-model="val"
checkbox  单一 v-model="bol" | 多个 value="lq|zq|ppq" v-model="val"  val: ["lq"]
radio value="male|famale"   v-model="val"   val: "male|famale"

条件渲染指令
v-show: 无论如何都渲染, display: block|none
v-if: 显示时渲染,不显示时不渲染,可以通过key对其建立渲染缓存
v-if v-else-if v-else(条件可以省略)  条件可以直接绑定一个条件表达式 | 返回值为布尔类型的方法

列表渲染指令
v-for="item in items"
items数据由vue实例的data提供,item为遍历items的元素值
数据可以为[] | {}
v-for="(v, i) in []"  v是元素值, i为元素索引
v-for="(v, k, i) in {}"  v是元素值, k为元素键, i为元素索引 (键值对)


组件
vue实际开发的模式: 组件化开发
什么是组件
组件有哪些
组件间的通信

1、根组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>根组件</title>
</head>
<body>
    <p>app之上</p>
    <div id="app">
        <h1>{{ msg }}</h1>
    </div>
    <p>app之下</p>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 通过new Vue创建的实例就是根组件(实例与组件一一对应,一个实例就是一个组件)
    // 每个组件组件均拥有模板,template
    var app = new Vue({
        // 根组件的模板就是挂载点
        el: "#app",
        data : {
            msg: "根组件"
        },
        // 根组件可以显式书写模板吗? 可以
        // 模板: 由""包裹的html代码块,出现在组件的内部,赋值给组件的$template变量
        // 根组件如果不书写自身模板,那么模板就采用挂载点,如果显式书写模块,就会替换挂载点,但根组件必须拥有挂载点
        template: "<div>显式模板</div>"
    })
    // app.$template
</script>
</html>

2、局部组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>局部组件</title>
    <style type="text/css">
        .sup {
            width: 100px;
            height: 100px;
            background-color: orange;
        }
        .sub {
            width: 100px;
            height: 100px;
            background-color: red;
            border-radius: 50%
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- 错误: html不区分大小写 -->
        <!-- <localTag></localTag> -->
        <!-- html中组件命名提倡-的链接语法 -->
        <!-- <local-tag></local-tag> -->
        
        <!-- 1 -->
        <!-- <localtag></localtag>
        <localtag></localtag>
        <localtag></localtag> -->

        <!-- 2 3 4 5 -->
        <local-tag></local-tag>

        <btn-tag></btn-tag>
        <btn-tag></btn-tag>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 如何定义一个局部组件
    // 局部组件的语法规则
    // 如何使用局部组件
    // 为什么要使用局部组件(达到html+css+js代码块的复用)

    // 一个满足vue语法规则的对象就是一个组件
    // 直接来定义这样的组件,用一个变量名来接收,就是创建了一个局部组件,
    // 变量名就是局部组件的组件名
    // 通过组件名就可以使用该组件

    // 局部组件要在父组件中使用,一定要提前在父组件中进行注册

    // 语法规则
    // 有自身模板template,有data/methods/computed/watch...
    var localTag = {
        template: "<div class='sup'><div class='sub'></div></div>"
    }

    var btnTag = {
        // template: "<div><button>按钮1</button><button>按钮2</button></div>"
        template: "<button @click='btnAction'>点击了{{ num }}下</button>",
        // data需要绑定方法,数据通过方法返回值进行处理,达到组件复用时,数据的私有化
        data: function() {
            return {
                num: 0
            }
        },
        methods: {
            btnAction: function () {
                this.num++
            }
        }
    }

    // 根组件
    new Vue({
        el: "#app",
        // 注册子组件
        components: {
            // 1
            // "localtag": localTag
            // 2
            // "localTag": localTag
            // 3
            // "local-tag": localTag
            // 4
            // localTag: localTag
            // 5 ES6对象语法,key value写法相同,可以省略value
            localTag,
            btnTag,

        }
    })
</script>
</html>

3、全局组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>全局组件</title>
</head>
<body>
    <div id="app">
        <global-tag v-for="(o, i) in ls" :key="i"></global-tag>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 全局组件
    // 用Vue.component("组件名", {})来创建全局组件
    // 全局组件附属于Vue实例,可以不需要注册就可以使用
    Vue.component("global-tag", {
        template: "<button @click='btnClick'>{{ n }}</button>",
        data () {
            return {
                n: 0
            }
        },
        methods: {
            btnClick () {
                this.n++
            }
        }
    })

    new Vue({
        el: "#app",
        data: {
            ls: [0, 0, 0]
        }
    })
</script>
</html>

4、父子组件和相互传递

  1、父组件传递数据给子组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>父传子</title>
</head>
<body>
    <div id="app">
        <local-tag :num="num" :sup_data="sup_data"></local-tag>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 父组件与子组件建立联系的关键点
    // 同绑定属性的方式进行数据传输
    // 1.给在父组件中出现的子组件名定义标签的全局属性
    // 2.全局属性的值赋值为父组件的数据变量
    // 3.在子组件内部,通过props拿到标签中的全局属性名

    var localTag = {
        props: ['num', 'sup_data'],
        template: "<div @click='divActive'>{{ num }}</div>",
        methods: {
            divActive () {
                console.log(this.num);
                console.log(this.sup_data);
            }
        }
    }

    // 数据属于父组件,子组件来接收使用数据
    new Vue({
        el: "#app",
        components: {
            localTag
        },
        data: {
            num: 10,
            sup_data: [1, 2, 3, 4, 5]
        }
    })
</script>
</html>

  2、子组件传递数据给父组件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>子传父</title>
</head>
<body>
    <div id="app">
        <global-tag @send_data="receive_data"></global-tag>
        {{ n }}
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    // 子传父:
    // 通过发生事件的方式进行数据传输
    // 数据由子组件提供, 父组件通过事件的回调方法获取数据
    // 发生数据的关键: $emit("事件名", ...args)
    Vue.component("global-tag", {
        template: "<div @click='divAction'>我是div</div>",
        data () {
            return {
                num: 10,
                arrList: [1, 2, 3, 4, 5]
            }
        },
        methods: {
            divAction () {
                // 发生事件
                // console.log("要发生事件,携带参数了");
                this.$emit("send_data", this.num, this.arrList)
            }
        }
    });

    new Vue({
        el: "#app",
        data: {
            n: 0
        },
        methods: {
            receive_data (num, arrList) {
                console.log("接收到的数据:", num, arrList);
                this.n = num;
            }
        }
    })
</script>
</html>

5、 todolist组件化

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>todoList案例</title>
</head>
<body>
    <div id="app">
        <div>
            <input type="text" v-model="val">
            <button type="button" @click="submitMsg">提交</button>
        </div>
        <ul>
            <!-- <li v-for="(v, i) in list" :key="i" @click="removeMsg(i)">{{ v }}</li> -->
            <todo-list v-for="(v, i) in list" :key="i" :v="v" :i="i" @delect_action="delect_action"></todo-list>
        </ul>
    </div>
</body>
<script src="js/vue-2.5.17.js"></script>
<script type="text/javascript">
    Vue.component("todo-list", {
        template: "<li @click='delect_action'><span>第{{ i + 1 }}条: </span><span>{{ v }}</span></li>",
        props: ['v', 'i'],
        methods: {
            delect_action () {
                this.$emit("delect_action", this.i)
            }
        }
    })
    

    new Vue({
        el: "#app",
        data: {
            val: "",
            list: []
        },
        methods: {
            submitMsg () {
                // 往list中添加input框中的value
                if (this.val) {
                    this.list.push(this.val);
                    this.val = ""
                }
            },
            delect_action(index) {
                this.list.splice(index, 1)
            }
        }
    })
</script>
</html>