表单指令 v-model 设置属性值

1.语法: v-model='控制value值的变量'
2. :value='变量'(属性指令),直接这样绑定数据不会实时更新数据(修改表单标签值,值不会实时映射给绑定变量)
3. v-model='变量'(表单指令),绑定的数据会实时更新(修改表单标签值,值会实时映射给绑定变量)
4. 单一复选框作为确认框时,v-model绑定的变量值为布尔类型,true代表选上该框,false则相反
5. 多个复选框时,v-model绑定的变量值是一个数据(可以看成列表),里面存放的数据是复选框中的value属性的对应值(放了谁,谁就会被选中)
6.单选框时, v-model绑定的变量值是单选框中value属性对应的值(里面放了谁,谁就会被选中)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>表单指令</title>

</head>
<body>
    <div id="app">
        <form action="">
            <!--表单指令语法: v-model='变量'-->
            <!--普通表单元素,用 v-model绑定的变量控制的是表单元素的value值-->
            <input type="text" v-model="v1">
            <input type="text" v-model="v2">
            <textarea name="" id="" cols="30" rows="10" v-model="v1"></textarea>

            <p>{{ v1 }}</p>  <!--通过表单指令,可以实时更新标签值,输入框v1值变,我也变,实时更新-->
            <hr>
            <p>{{ v2 }}</p>
            <hr>



            <!--单一复选框-->
            同意:
            <input type="checkbox" name="agree" v-model="v3">
            <hr>


            <!--多个复选框-->
            男:<input type="checkbox" name="hobbies" value="male" v-model="v4">
            女:<input type="checkbox" name="hobbies" value="female" v-model="v4">
            哇塞:<input type="checkbox" name="hobbies" value="others" v-model="v4">
            <p>{{ v4 }}</p>
            <hr>
            
            
            <!--单选框-->
            中午吃啥:<br>
            肉:<input type="radio" name="food" value="rou" v-model="v5">
            菜:<input type="radio" name="food" value="cai" v-model="v5">
         </form>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    // 1. 先产生Vue实例
    new Vue({
        el: '#app',
        data:{
            //普通表单元素
            // v1: '我是变量一',
            v1: '',
            v2: '我是变量二',

            //单一复选框
            // v3: true  // 给变量赋一个布尔值,true就会默认选上
            v3: false,    // false默认不选

            //多个复选框
            // v4: ['male', 'others'],
            v4: ['male', 'female', 'others'],  // 复选框的绑定变量的值是一个数组(列表),里面放的是复选框的value属性的值,放了谁,谁就会被选上

            //单选框
            // v5: 'cai',
            v5: 'rou'   // 单选框的绑定变量的值是单选框的value属性的值,放了谁,谁就会被选上
        }
    })
</script>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .p1 {
            width: 500px;
            height: 21px;
            background-color: orange;
        }
    </style>
</head>
<body>
    <div id="app">
        <form action="">
            <!--1) 对表单标签value进行绑定操作变量,不能时时检测绑定的变量-->
            <input class="inp1" type="text" :value="info">
            <input class="inp2" type="text" :value="info">
            <p class="p1">{{ info }}</p>
            <hr>
            <!--2) 表单标签的值由 v-model="变量" 来绑定控制,操作的还是value,但是拥有时时变量值的检测 -->
            <input class="inp1" type="text" v-model="info">
            <input class="inp2" type="text" v-model="info">
            <p class="p1">{{ info }}</p>
            <hr>
            <!-- 2) v-model操作单独复选框 - 确认框 -->
            是否同意:<input type="checkbox" name="agree" v-model="isAgree">
            <!--是否同意:<input type="checkbox" name="agree" true-value="yes" false-value="no" v-model="isAgree">-->
            <p>{{ isAgree }}</p>

            <!-- 3) 单选框-->
            性取向:
            男 <input type="radio" name="sex" value="male" v-model="mysex">
            女 <input type="radio" name="sex" value="female" v-model="mysex">
            哇塞 <input type="radio" name="sex" value="others" v-model="mysex">
            <p>{{ mysex }}</p>


            <!-- 4) 复选框-->
            兴趣爱好:
            男 <input type="checkbox" name="hobbies" value="male" v-model="myhobbies">
            女 <input type="checkbox" name="hobbies" value="female" v-model="myhobbies">
            哇塞 <input type="checkbox" name="hobbies" value="others" v-model="myhobbies">
            <p>{{ myhobbies }}</p>


            <hr>
            <input type="submit">
        </form>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            info: '123',
            isAgree: 0,
            // isAgree: 'no',
            mysex: 'others',
            myhobbies: ['male', 'female']
        }
    })
</script>
</html>

斗篷指令 v-cloak

1.斗篷指令作用:防止页面闪烁
	不处理情况下,由于我们的vue导入一般都是在页面的最后面(body后面),而每次打开该页面时,代码从上往下运行,会先渲染到{{ }},由于还没有被解析,页面会闪烁一下,当vue环境加载成功后,{{ }}才会被解析消失
	处理后,vue环境没被加载好时,#app是被隐藏的,当vue环境加载成功后,会依次#app的v-cloak属性,就不会出现{{ }}渲染闪烁问题。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>斗篷指令</title>
    <!--定义一个style标签,固定书写-->
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
    <!--引用定义的 v-cloak样式-->
    <div id="app" v-cloak>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
        <p>{{ msg }}</p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            msg: '我是斗篷指令'
        }
    })
</script>
</html>

**条件指令 **

v-if / v-show

v-if="false",为假时,在页面上不渲染,可以隐藏标签中的信息
v-show="false",为假时,在页面中用display: none渲染(隐藏),虽然没显示,但是任在页面结构

两种都是可以控制标签的显隐,绑定的值是布尔类型的值,当布尔值是false时,就是隐藏标签,当隐藏标签的时候
    v-if 是不渲染标签
    v-show以display:none方式渲染
        

**v-if / v-else-if / v-else **

v-if='变量'
v-else-if='变量'
v-else
一组分支,上分支成立会屏蔽掉下方所有分支,v-else分支没有条件,当所有的上分支都不成立时才显示v-else分支
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>条件指令</title>
</head>
<body>
    <div id="app">
        <!--条件指令-->
            <!--v-if="false",为假时,在页面上不渲染,可以隐藏标签中的信息-->
            <!--v-show="false",为假时,在页面中用display: none渲染(隐藏),虽然没显示,但是任在页面结构中-->
        <p v-if="true">if指令true</p>
        <p v-if="false">if指令false</p>
        <p v-show="true">shoe指令true</p>
        <p v-show="false">show指令false</p>

        <!--v-if是一个家族,有:
        v-if
        v-else-if
        v-else
        有以下特点:
        1.上分支成立,下分支会被屏蔽
        2.else分支只有在所有上分支都为假时才显示,且不需要条件-->
        <p v-if="v1==='1'">if分支</p>
        <p v-else-if="v1==='2'">else_if分支</p>
        <p v-els>else分支</p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            // v1: '1'
            // v1: '2'
            v1: '3'
        }

    })
</script>
</html>

条件指令小案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>条件指令案例</title>
    <style>
        .box{
            width: 400px;
            height: 200px;
        }
        .r{
            background-color: red;
        }
        .y{
            background-color: yellow;
        }
        .g{
            background-color: green;
        }

        /*显示高亮,给一个背景颜色,谁拿到这个属性,谁就是高亮*/
        .action{
            background-color: pink;
        }
    </style>
</head>
<body>
    <div id="app">
       <!--<p>-->
                            <!--通过判断 action属性有没有效来判断谁是高亮-->
            <!--<button @click="changeC('red')" :class="{action: c === 'red'}">红</button>-->
            <!--<button @click="changeC('yellow')" :class="{action: c === 'yellow'}">黄</button>-->
            <!--<button @click="changeC('green')" :class="{action: c === 'green'}">绿</button>-->
        <!--</p>-->
        <p>
            <button @click="changeC('red')">红</button>
            <button @click="changeC('yellow')" >黄</button>
            <button @click="changeC('green')" >绿</button>
        </p>
        <div class="wrap">
            <div class="box r" v-if="c ==='red'"></div>
            <div class="box y" v-else-if="c === 'yellow'"></div>
            <div class="box g" v-else></div>
        </div>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    // sessionStorage的生命周期与页面标签绑定,当标签页被关闭,数据库被清空
    // localStorage是前台永久数据库

    // sessionStorage.name = '123';
    // localStorage.name = 'xyz';
    // localStorage.clear();
    new Vue({
        el: '#app',
        data:{
            // c: 'red'
            // 页面重新刷新加载,可以从数据库中获取缓存,如果没有,再取默认值
            c: localStorage.c ? localStorage.c : 'red',
        },
        methods:{
            changeC(color){
                this.c = color;
                // 每一次改变c的值,将值同步到前台数据库
                localStorage.c = color;  // 存在永久数据库中
            }
        }

    })
</script>
</html>

循环指令 v-for

1) 遍历字符串:可以只逐一遍历字符,也可以连同遍历索引
    <p v-for="ch in str"></p> | <p v-for="(ch, index) in str"></p>
    
2) 遍历数组:可以只逐一遍历成员元素,也可以连同遍历索引
    <p v-for="ele in arr"></p> | <p v-for="(ele, index) in arr"></p>
    
3) 遍历字典:可以只逐一遍历值(value),也可以连同遍历成员键(key),还可以遍历成员key索引
  依次遍历value,key,key索引
    <p v-for="v in dic"></p> | <p v-for="(v,k) in arr"></p> | <p v-for="(v,k,i) in arr"></p>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>循环指令</title>
</head>
<body>
    <div id="app">
        <!--循环指令
        v-for=""
        语法:v-for="成员 in 容器"-->
        <!--字符串循环渲染: 可以只遍历值,也可以遍历值与索引-->
        <p>
            <span v-for="v in title">{{ v }}</span>
        </p>

        <p>
            <!--<span v-for="v in title">|{{ v }}</span>-->
            <span v-for="(v, i) in title"><span v-if="i !=0" > | </span>{{ v }}</span>
        </p>

        <!--数组循环渲染:可以只遍历值,也可以遍历值和索引-->
        <div>
            <!--<p v-for="v in arr">{{ v }}</p>-->
            <!--第一个参数永远代表值-->
            <!--<p v-for="(v, i) in arr">第{{ i }}元素:{{ v }}</p>-->
        </div>

        <!--对象循环渲染:可以只遍历值,也可以遍历值与键,还可以遍历值、键、索引-->
        <div>
             <!--遍历值value-->
            <!--<p v-for="v in people">{{ v }}</p>-->

            <!--遍历值与键, 第一个参数永远代表值-->
            <!--<p v-for="(v, k) in people">{{ k }}:{{ v }}</p>-->

            <!--遍历值、键、索引-->
            <p v-for="(v, k, i) in people">{{ i }}-{{ k }}:{{ v }}</p>
        </div>
        <br>
        <div>
            <div v-for="(stu, i) in stus">
                <hr v-if="i != 0">
                <p v-for="(v, k) in stu">{{ i }}-{{ k }}:{{ v }}</p>
            </div>
        </div>

    </div>
</body>
<script src="js/vue.js"></script>
<script>
     new Vue({
        el: '#app',
        data: {
            title: '循环指令',
            arr: [1,2,3,4],
            people: {
                name: '兔子',
                age: 18,
                price: 6.66
            },
            stus: [
                {
                    name: "Bob",
                    age: 18
                },
                {
                    name: "Tom",
                    age: 17
                },
                {
                    name: "Jerry",
                    age: 19
                }
            ]
        }
    })
</script>
</html>
<div id="app">
    <div>
        <span v-for="ch in str">{{ ch }}</span>   #循环字符串
    </div>
    <div>
        <!--针对循环遍历的标签,通过会提供key属性来优化渲染速度,但key的值必须唯一(key可以不用提供) -->
        <span v-for="(ch, i) in str" :key="ch + i">{{ i }}{{ ch }}</span>
    </div>
    <div>
        <p v-for="(ele, i) in arr">{{ i }}{{ ele }}</p>  #循环数组
    </div>


    <div>
        <p v-for="ele in dic">{{ ele }}</p>   #循环字典
    </div>

    <div>
        <p v-for="(ele, k) in dic">{{ k }}:{{ ele }}</p>
    </div>

    <div>
  
        <p v-for="(ele, k, i) in dic">{{ i }}{{ k }}:{{ ele }}</p>  #依次取出字典的value,key,key索引
    </div>

</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            str: 'abc123呵呵',
            arr: [3, 4, 1, 2, 5],
            dic: {
                name: 'Tank',
                age: 80,
                gender: '哇塞',
            }
        }
    })
</script>

循环案列

留言板案例

1) 留言就是往留言数组中添加数据,删除留言就是从留言数组中移除数据

2) 前台数据库:localStorage 和 sessionStorage
    localStorage永久保存数据  (这次案例以localStroage保存)
    sessionStorage临时保存数据(当所属页面标签被关闭,数据被清空)
3) 前台localStorage 和 sessionStorage数据库存储的值是字符串类型,所以要存放arr、dic等复杂数据需要JSON参与

点击留言按钮就把输入框中的留言保存在下面,再点击留言就是删除

push是尾增,unshift是首增

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        li:hover {
            color: red;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div id="app">
        <p>
            <input type="text" v-model="userMsg">  #获取输入框的值userMsg并且传递给data
            <button type="button" @click="sendMsg">留言</button>
        </p>
        <ul>
            <li v-for="(msg, index) in msgs" @click="deleteMsg(index)">
                {{ msg }}
            </li>
        </ul>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msgs: localStorage.msgs ? JSON.parse(localStorage.msgs) : [],  // 从数据库中取出所有留言,没有就显示[]
            userMsg: '',  // 用户留言
        },
        methods: {
            sendMsg() {  // 留言事件
                // 尾增
                // this.msgs.push(this.userMsg);
                // 首增
                // this.msgs.unshift(this.userMsg);

                let userMsg = this.userMsg;
                if (userMsg) {    //判断用户输入的留言是否存在
                    this.msgs.unshift(userMsg);  // 渲染给页面
                    localStorage.msgs = JSON.stringify(this.msgs);  // 同步到数据库
                    this.userMsg = '';  // 清空留言框
                }
            },
            deleteMsg(index) {   //删除操作
                // 开始索引  操作长度  操作的结果们  (括号里面三个参数,最后一个参数操作的结果不写就是删除的意思)
                this.msgs.splice(index, 1)
            }
        }
    })
</script>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <div id="app">
        <input type="text" v-model="msg">
        <button @click="send_comment">留言</button>
        <ul>
            <li v-for="(v, i) in comments" @click="deleteMsg(i)">{{ v }}</li>
        </ul>
    </div>
</body>
<script src="../js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: '',
            comments: []
        },
        methods: {
            send_comment() {
                // 数组的增
                // push pop unshift shift splice
                // this.comments.unshift(this.msg);
                // this.comments.splice(0,0,0);
                if (this.msg) {
                    this.comments.push(this.msg);  // 留言
                    this.msg = '';  // 留言后清空输入框
                }
            },
            deleteMsg(index) {
                this.comments.splice(index, 1);
            }
        }
    })
</script>
<script>

    // 数组操作万能方法,可以完成增删改
    let arr = [1, 2, 3];
    // 参数:开始索引,操作长度,操作的结果们
    arr.splice(2, 0, 100);
    arr.splice(1, 1);
    console.log(arr);

</script>

</html>

分隔符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>分隔符</title>
</head>
<body>
    <div id="app">
        <!--先要求不要vue进行渲染,要采用分隔符-->
        <p>{{ num }}</p>
        <hr>
        <!--如以下定义有分隔符就要采用分隔符形式书写才会被渲染-->
        <p>{ num ]}</p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            num: 100
        },
        // 用来修改插值表达式符号
        delimiters: ['{',']}']
    })
</script>
</html>

计算属性成员

1.computed是用来声明 方法属性 的
2. 声明的方法属性不能在 data 中重复定义
3. 方法属性必须在页面中渲染使用,才会对内部出现的所有变量进行监听
4.计算属性的值来源于监听方法的返回值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>计算成员属性</title>
</head>
<body>
    <div id="app">
        <input type="text" v-model="v1">
        +
        <input type="text" v-model="v2">
        =
        <button>{{ res }}</button>

    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data:{
            v1: '',
            v2: '',
            // res: '结果'  computed中定义了data中就不需要定义
        },
        //1. computed中定义的是方法属性,data中定义的也是方法属性,所以不需要重复定义(省去data中)
        //2. 方式属性的值来源于绑定的方法的返回值
        //3.方法属性必须在页面中渲染后,绑定的方法才会被调用
        //4.方法中出现的所有变量都会被监听,任何变量发生值更新都会调用一次绑定方法,重新更新一下方法属性的值
        //5. 方法属性值不能手动设置,必须通过绑定的方法进行设置
        computed:{
            // 这里的 res 相当于一个函数方法
            res() {
                // this.v1、this.v2 拿到的值是字符串,转换成数字用+号:+this.v1、+this.v2
                return this.v1 && this.v2 ? +this.v1 + +this.v2: '结果'
            }
        }
    })
</script>
</html>

把两个输入框的值合并,用{{flName}}渲染出来

<div id="app">
    姓:<input type="text" v-model="fName">
    名:<input type="text" v-model="lName">
    姓名:<b>{{ flName }}</b>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            fName: '',
            lName: '',
        },
        computed: {
            flName(){
                // this.fName和this.lName有值发送改变,该方法都会被调用
                // 变量flName的值是由函数的返回值决定
                return this.fName + this.lName;
            }
        }
    })
</script>

监听实例 watch

1.watch为data中已存在的属性设置监听方法
2.监听的属性值发生改变,就会触发监听方法
3.监听方法的返回值没有意义

监听一个值,然后拆分两份

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>属性监听</title>
</head>
<body>
    <div id="app">
        <p>
            姓名:<input type="text" v-model="full_name">
        </p>
        <p>
            姓:<span>{{ first_name }}</span>
        </p>
        <p>
            名:<span>{{ last_name }}</span>
        </p>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            full_name: '',
            first_name: '',
            last_name: ''
        },
        watch:{
            //1.watch中给已有的属性设置监听方法
            //2.监听的属性值一旦发生更新,就会调用监听方法,在方法中完成相应逻辑
            //3.监听方法不需要返回值(返回值只有主动结束方法的作用)
            full_name(){
                // fullName值改变,就会调用绑定的事件方法
                if (this.full_name.length === 2){
                    k_v_arr = this.full_name.split('');
                    this.first_name = k_v_arr[0];
                    this.last_name = k_v_arr[1]
                }
            }
        }
    })
</script>
</html>

组件

// 1) 组件:一个包含html、css、js独立的集合体,这样的集合体可以完成页面解构的代码复用
// 2) 分组分为根组件、全局组件与局部组件
//      根组件:所有被new Vue()产生的组件,在项目开发阶段,一个项目只会出现一个根组件
//      全局组件:不用注册,就可以成为任何一个组件的子组件
//      局部组件:必须注册,才可以成为注册该局部组件的子组件
// 3) 每一个组件都有自身的html结构,css样式,js逻辑
//      每一个组件其实都有自己的template,就是用来标识自己html结构的
//      template模板中有且只有一个根标签
//      根组件一般不提供template,就由挂载点的真实DOM提供html结构
// 4) 除根组件的其他组件,数据要有局部作用域,保证组件复用时,各组件间数据的独立性
// 5) 在多组件共处时,在哪个组件模板中出现的变量,有当前组件组件提供
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>组件</title>
</head>
<body>
    <div id="app">
        {{ msg }}
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    /**
     * 1.组件:由html、css、js三部分组成的独立单位,可以类似于变量,重复使用
     * 2.组件其实就是vue实例(对象),一个组件就是一个vue实例(对象)
     * 3.new Vue()产生的也是实例对象,所以也是组件,我们称之为 根组件
     *      一个页面建议只出现一个根组件(项目开发模式下,一个项目建议只出现一个根组件)
     * 4.组件的html页面结构由 template 实例成员提供
     *      template提供的html结构是用来构建虚拟DOM的
     *      真实DOM最终会被虚拟DOM替换
     *      根组件一般不提供 template , 由挂载点el来提供构建虚拟DOM的页面结构,根组件如果提供了template,还需要设置挂载点作为替换占位符
     *      template 模板有且只有一个根标签
     */
    let c1 = '';
    new Vue({
        el: '#app',
        data: {
            msg: 100,
            c1: 'red',
        },
        template: `
                <div id='app'>
                    <p :style="{color: c1}">{{ msg }}</p>
                    <p @click="clickAction">{{ msg }}</p>
                </div>  `,
        methods: {
            clickAction(){
                console.log(this.msg)
            }
        }
    })
</script>
</html>

局部组件

// 1) 创建局部组件
// 2) 在父组件中注册该局部组件   根组件称为父组件
// 3) 在父组件的template模板中渲染该局部组件
<style>
    .box {
        box-shadow: 0 3px 5px 0 #666;
        width: 240px;
        height: 300px;
        text-align: center;
        padding: 20px 0;
        float: left;
        margin: 5px;
    }
    .box img {
        width: 200px;
    }
</style>
<div id="app">
    <!--<mcc></mcc>-->
  //3.在父组件模板中渲染局部组件
    <local-tag></local-tag>
    <local-tag></local-tag>
</div>
<script src="js/vue.js"></script>
<script>

  //1.创建局部组件
    let localTag = {
        template: `
        <div class="box">
            <img src="img/666.jpg" alt="">
            <h3>凤哥</h3>
            <p>马叉虫❤马叉虫</p>
        </div>
        `
    };

    new Vue({
        el: '#app',
        components: {  //2.在父组件中注册局部组件
            // mcc: localTag,
            // localTag,
            'local-tag': localTag,
        }
    })
</script>

子组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset='UTF-8'>
    <title>子组件</title>
</head>
<body>
    <!--根组件的 template-->
    <div id="app">
        <my-tag></my-tag>
        <my-tag></my-tag>
        <my-tag></my-tag>

        <tag></tag>
    </div>
</body>
<script src="js/vue.js"></script>
<script>
    //1.定义组件
    //2.注册组件
    //3.使用组件

    //如何定义子组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件
    let myTag = {
        template:  `
        <div>
            <h3>子组件</h3>
            <p>我是自定义子组件</p>
</div>
        `,
    };

    //了解:全局组件,不要注册就可以直接使用
    Vue.component('tag',{
        template:`
        <div>
        <h3>全局组件</h3>
        <p>我是自定义的全局组件</p>
</div>`,
    });

    new Vue({
        el: '#app',
        components:{
            myTag,
        }
    })

</script>
</html>

全局组件

// 1) 创建全局组件
// 2) 在父组件的template模板中直接渲染该全局组件
<style>
    .box {
        box-shadow: 0 3px 5px 0 #666;
        width: 240px;
        height: 300px;
        text-align: center;
        padding: 20px 0;
        float: left;
        margin: 5px;
    }
    .box img {
        width: 200px;
    }
</style>
<div id="app">
  //2.父组件模板渲染全局组件
    <global-tag></global-tag>
    <global-tag></global-tag>
    <global-tag></global-tag>
</div>
<script src="js/vue.js"></script>
<script>
   //1.注册全局组件
    Vue.component('global-tag', {
        template: `
        <div class="box" @click="action">
            <img src="img/666.jpg" alt="">
            <h3>凤哥</h3>
            <p>马叉虫❤{{ num }}</p>
        </div>
        `,
        data () {
            return {
                num: 0
            }
        },
        methods: {
            action() {
                this.num++;
            }
        }
    });

    new Vue({
        el: '#app',
    })
</script>