通过一系列vue-demo入门vue2

一、创建简单vue实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hello world</title>
    <!-- 引入vue.js文件创建vue实例 -->
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">{{content}}</div>
    <!-- <div>{{content}}</div> -->

    <script>
        // var dom = document.getElementById('app');
        // dom.innerHTML = "Hello World!"
        // setTimeout(function(){
        //     dom.innerHtml='bye world'
        // },2000)

        var app = new Vue({
            el: '#app',
            data: {
                content: 'hello world!'
            }
        })
        setTimeout(function () {
            app.$data.content = 'bye world!'
        }, 2000)
    </script>
</body>

</html>

二、实现todoList

1.通过简单vue实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>todo list</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <input type='text' v-model="inputValue" />
        <button v-on:click="handleBtnClick">提交</button>
        <ul>
            <!-- <li>第一课的内容</li>
            <li>第二课的内容</li> -->
            <li v-for="item in list">{{item}}</li>
        </ul>
    </div>

    <script>
        var app = new Vue({
            el: '#app',
            data: {
                list: [],
                inputValue:''
            },
            methods: {
                handleBtnClick: function () {
                    // alert('click')
                    this.list.push(this.inputValue);
                    this.inputValue=''
                }
            }
        })
    </script>
</body>

</html>

2.通过jquery

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>todoList Jquery</title>
    <script src='./jquery.js'></script>
</head>

<body>
    <div>
        <input id="input" type='text' />
        <button id="btn">提交</button>
        <ul id="list">
        </ul>
    </div>

    <script>
        function Page() {

        }
        $.extend(Page.prototype, {
            init: function () {
                this.bindEvents()
            },
            bindEvents: function () {
                var btn = $('#btn');
                // proxy方法 会改变handleBtnClick方法的this指向,使其一直是指向这个page实例
                btn.on('click', $.proxy(this.handleBtnClick, this))
            },
            handleBtnClick: function () {
                // alert('123')
                var inputElem = $("#input");
                // 获取Input框的内容
                var inputValue = inputElem.val();
                // 将其添加到ul里面
                var ulElem = $("#list");
                ulElem.append('<li>' + inputValue + '</li>');
                // input框内容再置空
                inputElem.val('');
            }
        })

        var page = new Page();
        page.init();
    </script>
</body>

</html>

三、全局组件、局部组件、简单父传子、子传父

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>todo list</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <input type='text' v-model="inputValue" />
        <button v-on:click="handleBtnClick">提交</button>
        <ul>
            <li v-for="item in list">{{item}}</li>
            <!-- <todo-item v-bind:content="item" v-for="item in list">
            </todo-item> -->
        </ul>
    </div>

    <script>
        // 全局组件
        // Vue.component("TodoItem",{
        //     template:"<li>todo item</li>"
        // })
        // Vue.component("TodoItem",{
        //     props:['content'],
        //     template:"<li>{{content}}</li>"
        // })
        // 局部组件
        // var TodoItem = {
        //     props: ['content'],
        //     template: "<li>{{content}}</li>"
        // }

        var app = new Vue({
            el: '#app',
            components: { TodoItem: TodoItem },
            data: {
                list: [],
                inputValue: ''
            },
            methods: {
                handleBtnClick: function () {
                    // alert('click')
                    this.list.push(this.inputValue);
                    this.inputValue = ''
                }
            }
        })
    </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>todo list</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <input type='text' v-model="inputValue" />
        <button v-on:click="handleBtnClick">提交</button>
        <ul>
            <todo-item 
            v-bind:content="item" 
            v-bind:key="index" 
            v-for="(item,index) in list" 
            v-on:delete="handleItemDelete(index)">
            </todo-item>
        </ul>
    </div>

    <script>
        // 局部组件
        var TodoItem = {
            props: ['content','index'],
            template: "<li v-on:click='handleItemClick'>{{content}}</li>",
            methods: {
                handleItemClick: function () {
                    this.$emit("delete",this.index);
                }
            }
        }

        var app = new Vue({
            el: '#root',
            components: { TodoItem: TodoItem },
            data: {
                list: [],
                inputValue: ''
            },
            methods: {
                handleBtnClick: function () {
                    // alert('click')
                    this.list.push(this.inputValue);
                    this.inputValue = ''
                },
                handleItemDelete: function (index) {
                    // alert('delete')
                    this.list.splice(index,1)
                }
            }
        })
    </script>
</body>

</html>

四、两种创建vue实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hello world</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root" @click="handleCLick">{{message}}
        <item></item>
    </div>

    <script>
        // 全局组件Vue.component(),不用在父组件当中components中再注册
        Vue.component("item",{
            template:"<p>hello item</p>"
        })
        // 根实例
        var vm = new Vue({
            el: "#root",
            data: {
                message: "hello world!"
            },
            methods: {
                handleCLick: function () {
                    alert('hello world!');
                }
            }
            // props computed watch
        })
    </script>
</body>

</html>

五、vue实例生命周期

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>生命周期</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">111111</div>

    <script>
        // 生命周期函数就是vue实例在某个"时间点"会"自动执行"的函数
        // 注意生命周期钩子没有定义在methods里面
        // 下面一共8个生命周期钩子,其实vue源码当中是11个,点击vue官网的学习->API
        // activated()  deactivated()  errorCaptured()  在后面的学习当中会给演示说明
        var vm = new Vue({
            el: "#app",
            template: "<div>{{test}}</div>",
            data: {
                test: "hello world!"
            },
            beforeCreate: function () {
                console.log("beforeCreate");
            },
            created: function () {
                console.log("created")
            },
            // 接着会询问是否有el选项
            // 然后询问有无template选项
            // 有template,就把模板内容直接渲染
            // 无template,就把el接管的dom标签的全部内容当做模板template来进行渲染 
            // 在渲染之前,也就是在模板和数据相结合之前的一瞬间,会执行beforeMount函数
            beforeMount: function () {
                console.log(this.$el);
                console.log("beforeMount");
                // alert("beforeMount");
            },
            // beforeMount执行后,模板和数据结合后生成的vue实例当中的dom元素会挂载(显示)到页面之上
            // vue实例挂载之后,会执行mounted()
            mounted: function () {
                //上面的和这行的$el反映出mounted执行后页面才渲染完毕
                // 这里的$el才打印出模板template中的内容
                console.log(this.$el);
                console.log("mounted");
            },
            // 下面有两个beforeDestroy()和destroyed()
            // 但是到页面刷新后发现并没有执行,那么它们什么时候会被执行呢?
            // 答:只有当vm.$destroy()方法被调用执行之后才会触发这两个生命周期钩子
            // 组件即将被销毁时 beforeDestroy
            beforeDestroy: function () {
                console.log("beforeDestroy");
            },
            // 组件被完全销毁后 destroyed            
            destroyed: function () {
                console.log("destroyed");
            },
            // 下面有两个beforeUpdate()和updated()
            // 但是到页面刷新后发现并没有执行,那么它们什么时候会被执行呢?
            // 答:只有当数据发生改变之后才会触发这两个生命周期钩子
            // 打开控制台 vm.test="zhangsan" 或 vm.$data.$test="zhangsan"
            // 数据发生改变但还没重新渲染之前 beforeUpdate
            beforeUpdate: function () {
                console.log("beforeUpdate");
            },
            // 重新渲染之后 updated
            updated: function () {
                console.log("updated");
            },
        })
    </script>
</body>

</html>

六、vue模板语法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>模板语法</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <div>{{name+" Lee"}}</div>
        <div v-text="name+' Lee'"></div>
        <div v-html="name+' Lee'"></div>
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                name: "Dell"
            }
        })
    </script>
</body>

</html>

七、计算属性computed、方法method、侦听器watch

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算属性方法侦听器</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <!--冗余的 插值表达式 -->
        <!-- {{firstName+" "+lastName}} -->
        <!--1 计算属性computed -->
        <!-- {{fullName}}  -->
        <!--2 方法methods -->
        <!-- {{fullName()}}  -->
        <!--3 侦听器watch -->
        {{fullName}} {{age}}
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                firstName: "Dell",
                lastName: "Lee",
                // 下面这样会数据冗余
                fullName: "Dell Lee",
                age: 28
            },
            // computed watch methods  若三者都可实现某种功能,推荐使用computed

            // 侦听器(有缓存,只要侦听的变量所依赖的不变化,就不执行,用缓存)
            // 即watch与computed很类似都有缓存机制,但是推荐computed
            // watch: {
            //     firstName: function () {
            //         console.log("计算了一次firstName");
            //         this.fullName = this.firstName + " " + this.lastName;
            //     },
            //     lastName: function () {
            //         console.log("计算了一次lastName");
            //         this.fullName = this.firstName + " " + this.lastName;
            //     }
            // },

            // 方法(无缓存特点,只要页面渲染一次,方法就会重新执行一次)
            // 测试:vm.lastname="liu" 会打印“计算了一次”
            // 测试:vm.age=27 也会打印“计算了一次”
            // methods: {
            //     fullName: function () {
            //         console.log("计算了一次");
            //         return this.firstName + " " + this.lastName;
            //     }
            // }

            // 计算属性(内置缓存的特点:若计算属性依赖的值没有发生变化,就不会执行)
            // 测试:vm.age=27 不会打印“计算了一次”
            // 测试:vm.lastname="liu" 会打印“计算了一次”
            // computed: {
            //     fullName: function () {
            //         console.log("计算了一次");
            //         return this.firstName + " " + this.lastName;
            //     }
            // }
        })
    </script>
</body>

</html>

八、计算属性setter-getter

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算属性-setter+getter</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        {{fullName}}
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                firstName: "Dell",
                lastName: "Lee"
            },
            computed: {
                // fullName: function () {
                //     return this.firstName + " " + this.lastName;
                // }
                fullName: {
                    get: function () {
                        return this.firstName + " " + this.lastName;
                    },
                    set: function (value) {
                        // console.log(value);
                        var arr = value.split(" ");
                        // 因为firstName和lastName重新赋值了,所以执行set()后会引起上面的get()的执行
                        this.firstName = arr[0];
                        this.lastName = arr[1];
                    }
                }
            }
        })
    </script>
</body>

</html>

九、vue样式绑定

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>样式绑定</title>
    <script src='./vue.js'></script>
    <style>
        .activated {
            color: red;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- class 对象-->
        <!-- 样式和数据的一个绑定,我们把这个叫做class的对象绑定 -->
        <!-- :class="{activated:isActivated}" -->
        <!-- class 数组-->        
        <!-- 可绑定多个样式名 -->
        <!-- :class="[activated,activatedOne]" -->
        <!-- style 对象-->
        <!-- :style="styleObj" -->
        <!-- style 数组 除此之外其他代码同上面style 对象形式-->
        <!--  :style="[styleObj]" -->
        <!-- style 数组(可以放多个对象 -->
        <!--  :style="[styleObj,{fontSize:'20px'}]" -->
        <div :style="[styleObj, {fontSize:'20px'}]" @click="handleDivClick">
            hello world
        </div>
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                // isActivated:false
                // activated: '',
                // activatedOne:"activated-one",
                styleObj: {
                    color: "black"
                }
            },
            methods: {
                handleDivClick: function () {
                    // class :class="{activated:isActivated}"
                    // this.isActivated = !this.isActivated;
                    // class :class="[activated]"
                    // this.activated = this.activated === "activated" ? "" : "activated";
                    // style
                    this.styleObj.color = this.styleObj.color === "black" ? "red" : "black";
                }
            }
        })
    </script>
</body>

</html>

十、vue条件渲染 v-if v-show

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>条件渲染</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <!-- v-if和v-show -->
        <!-- v-if 直接不挂载,不存在页面dom之上 -->
        <!-- v-show 是不显示 display:none -->
        <!-- v-show的性能较高,因为不会频繁移除dom -->
        <!-- <div v-if="show" data-test="v-if">{{message}}</div>
        <div v-if="show" data-test="v-if">{{message}}</div> -->

        <!-- v-if和v-else -->
        <!-- v-else不必绑定变量,但这两个指令所在的标签必须紧贴使用,中间不可放其他标签,比如放一个<span></span>  -->
        <!-- 有你没我,有我没你,dom树上只挂载其中一个 -->
        <!-- <div v-if="show">{{message}}</div>
        <div v-else>bye world</div> -->

        <!-- v-if和v-else-if和v-else -->
        <!-- 注意这三者也是有紧贴着使用 -->
        <!-- <div v-if="show==='a'">This is A</div>
        <div v-else-if="show==='b'">This is B</div>
        <div v-else>This is Others</div> -->

        <!-- 简单例子 -->
        <!-- 问题:vue的虚拟dom机制会尽量复用页面上的dom -->
        <!-- 比如下面如果<input/>,在切换用户名和邮箱名的时候,Input框会复用,即内容不会清空 -->
        <!-- 解决方案,给<input key="" /> 这样vue会知道是唯一元素,就不会复用它-->
        <!-- <div v-if="show">
            用户名:<input key="userName"/>
        </div>
        <div v-else>
            邮箱名:<input key="emailName"/>
        </div> -->

    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                show:false,
                // show: 'a',
                message: "hello world!"
            }
        })
    </script>
</body>

</html>

十一、vue列表渲染 v-for

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表渲染</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <!-- 数组的循环 -->

        <!-- <div v-for="item in list"></div> -->
        <!-- 更推荐用of这个语法 -->   
        <!-- 为了提高循环性能,推荐给每一个循环项加上唯一的key值-->
        <!-- 但是key不推荐用这里的index,推荐使用后端返回的id标识,即item.id -->
        <!-- <div v-for="(item,index) of list"
            :key="item.id">
            {{item.text}}---{{index}}
        </div> -->

        <!-- template 占位符 在sources中不显示这个标签,即并不会渲染到页面之上 -->
        <!-- 需要一个新的标签包裹使其只循环一次但是又不想用div-->
        <!-- <template v-for="(item,index) of list">
            <div>
                {{item.text}}---{{index}}
            </div>
            <span>
                {{item.text}}---{{index}}
            </span>
        </template> -->


        <!-- 对象的循环 -->
        <!-- vm.userInfo.name="Dell Lee" 操作已有的key值 数据变 页面变-->
        <!-- vm.userInfo.address="Beijing" 操作没有的key值 数据变 页面不变-->
        <!-- 如何解决这种问题,想添加新的Key值? -->
        <!-- 答:和上面数组一样的方法,改变对象的引用。 vm.userInfo={新对象新的Key和value值} -->
        <!-- 但其实还有set方法,见下一节内容 -->
        <div v-for="(item,key,index) of userInfo">
            {{item}}---{{key}}---{{index}}
        </div>
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            // vm.list.push({id:"26419",text:"try"})  成功  数据变 页面变
            // vm.list[4]={id:"26419",text:"try"}  失败  数据变 页面不变
            // 注意:我们不能通过下标方式来操作数组,只能通过vue提供的七种数组变异方法来操作数组
            // 数组尾部添加删除push pop
            // 数组头部添加删除shift unshift
            // 截取splice 排序sort 取反reverse

            // 除了上面七种方法,可以有别的方法吗?
            // 答:改变数组的引用地址,即直接给List赋值 vm.list=[新数组]
            // 还可以用set方法,见下一节内容
            // data: {
            //     list: [{
            //         id:"1628640",
            //         text:"hello"
            //     },{
            //         id:"6924155",
            //         text:"Dell"
            //     },{
            //         id:"0174746",
            //         text:"Lee"
            //     }]
            // }

            // 对象
            data:{
                userInfo:{
                    name:"Dell",
                    age:28,
                    gender:"male",
                    salary:"secret"
                }
            }
        })
    </script>
</body>

</html>

十二、vue-set

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue-set</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <!-- 对象 -->
        <!-- <div v-for="(item,key,index) of userInfo">
            {{item}}---{{key}}---{{index}}
        </div> -->

        <!-- 数组 -->
        <div v-for="(item,index) of userInfo">
                {{item}}---{{index}}
        </div>
    </div>

    <script>
        // 对象
        // set即是全局方法,也是实例方法
        // 全局方法
        // Vue.set(vm.userInfo,"address","Beijing")
        // 实例方法
        // vm.$set(vm.userInfo,"address","Beijing")

        // 数组
        // 全局方法 Vue.set(vm.userInfo,2,10)
        // 实例方法 vm.$set(vm.userInfo,3,100)

        // 改数组(数据变,页面变)
        // (1) 七种变异方法 (2) 改变引用地址 (3)set
        // 改对象(数据变,页面变)
        // (1) 改变引用地址 (2)set
        var vm = new Vue({
            el: "#app",
            data: {
                // userInfo: {
                //     name: "Dell",
                //     age: 28,
                //     gender: "male",
                //     salary: "secret"
                // }
                userInfo:[1,2,3,4]
            }
        })
    </script>
</body>

</html>

十三、事件绑定 v-on、@click

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>事件绑定</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="app">
        <!-- @click="handleClick()"这样写会触发点击事件,但是获取不到事件对象e,可写成@click="handleClick($event)"  -->
        <!--写法1 <button @click="handleClick($event)">Button</button> -->
        <!--写法2 <button @click="handleClick">Button</button> -->
        <!--写法1加括号,可以传参 @click="handleClick($event,1,2,3)" -->
        <!-- <button @click="handleClick($event,1,2,3)">Button</button> -->

        <!-- "/abc" 为提交form表单后的跳转地址 -->
        <!-- 为阻止这个默认跳转的行为,可在handleClick()函数内写上e.preventDefault(); -->
        <!-- 当然也可这样 <form action="/abc" @click.prevent> 便可实现完全一致的功能-->
        <!-- 这是vue提供的修饰符,上面也可写成 @click.prevent="handleClick" -->
        <!-- <form action="/abc" @click.prevent>
            <input type="submit" />
        </form> -->

        <!-- 这样的基础事件修饰符还有很多,如下 -->

        <!-- 普通修饰符 -->
        <!-- @click.prevent   阻止默认行为  e.preventDefault()-->
        <!-- @click.stop   阻止事件冒泡  e.stopPropagation()-->
        <!-- @click.self   只有e.target=e.currentTarget的时候才会执行。即只有触发元素和绑定元素一致时才会触发事件执行-->
        <!-- @click.once   只执行一次事件 -->
        <!-- @click.capture   事件冒泡——>事件捕获规则,当然是父和子元素都加上.capture -->
        
        <!-- @click.stop   点击子元素时,若父元素也监听同样事件,将 不会冒泡到父元素身上-->
        <!-- @click.self   只有点击标签自身的时候才会触发点击事件。点击其子元素时不触发。点击父元素也不触发。-->
        <!-- @click.capture   按道理是按事件冒泡,由子到父的顺序,先触发子的事件再触发父的事件。 -->
        <!-- 若加上capture的话,就事件捕获,即由父到子的顺序,先触发父的事件再触发子的事件 -->
       
        <!-- <div @click.capture="handle">love
                <div @click.capture="handleClick">hello world</div>
        </div> -->

        <!-- 按键修饰符 -->
        <!-- @keydown.enter 只有点击enter键时候才会执行后面的函数 -->
        <!-- @keydown.esc @keydown.tab @keydown.delete 等等 -->
        <!-- <input @keydown.enter="handleKeyDown" /> -->

        <!-- 系统修饰符 -->
        <!-- 和按键修饰符差不多,有四个 -->
        <!-- @keydown.ctrl -->
        <!-- @keydown.alt -->
        <!-- @keydown.shift -->
        <!-- @keydown.meta 有些特殊键盘有这个键-->
        <!-- 即要想执行后面的函数,关按键是不够的,还需要按下对应的系统键 -->
        <!-- <input @keydown.shift="handleKeyDown" /> -->

        <!-- 鼠标修饰符 -->
        <!-- @click.right  监听鼠标右键的点击事件 -->
        <!-- @click.left  监听鼠标左键的点击事件 -->
        <!-- @click.middle  监听鼠标中键的点击事件 -->
        <!-- <div @click.right="handleMouseClick">click</div> -->
          

    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            methods: {
                handleClick: function (e) {
                    console.log("儿子");
                },
                handle: function (e) {
                    console.log("爸爸");
                },
                handleKeyDown:function(e){
                    console.log(e.target.value)
                },
                handleMouseClick:function(e){
                    console.log("right")
                }
            }
        })
    </script>
</body>

</html>

十四、表单绑定v-model

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>表单绑定</title>
    <script src='./vue.js'></script>
</head>

<body>
    <!-- 表单绑定主要是指 v-model -->
    <!-- v-model不仅可以用于 <input>标签还可以 -->
    <div id="app">
        <!-- <input v-model="value" type="text"> -->
        <!-- <textarea v-model="value"></textarea> -->
        <!-- <input v-model="value" type="checkbox"> -->
        <!-- <input v-model="value" type="radio" value="test"> -->
        <!-- select v-model的value值优先选择option里的value(1,2,3),没有value才选择innerHtml(A,B,C) -->
        <!-- <select v-model="value">
            <option disabled>----请选择-----</option>  这个是为了更好的用户体验
            <option value="1">A</option>
            <option value="2">B</option>
            <option value="3">C</option>
        </select> -->
        <!-- {{value}} -->

        <!-- 表单修饰符 -->
        <!-- <input type="text" v-model.lazy="value" /> -->
        <!-- <input type="text" v-model.number="value" /> -->
        <!-- <input type="text" v-model.trim="value" /> -->
        <!-- v-model.number 不加时,123也会判断为string类型,加了之后会把能转换为number类型的都转换为number类型再输出 -->
        <!-- v-model.lazy  当输入框失焦的时候才输出 -->
        <!-- v-model.trim  去首尾空格修饰符后才输出 -->
        {{value}}
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data:{
                value:""
            },
            watch:{
                value:function(){
                    console.log(typeof this.value)
                }
            }
        })
    </script>
</body>

</html>

十五、组件细节点

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件细节点</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- 知识点1 用is解决h5标签上的一些小bug-->
        <!-- 因为tbody里面只能接<tr> -->
        <!-- 因为ul里面只能接<li> -->
        <!-- 因为ol里面只能接<li> -->
        <!-- 因为select里面只能接<option> -->
        <!-- 故以上的都用 is属性来接所设置的子组件名字 -->
        <!-- <table>
            <tbody>
                <tr is="row"></tr>
                <tr is="row"></tr>
                <tr is="row"></tr>
            </tbody>
        </table>
        <table>
            <ul>
                <li is="row"></li>
                <li is="row"></li>
                <li is="row"></li>
            </ul>
        </table>
        <table>
            <ol>
                <li is="row"></li>
                <li is="row"></li>
                <li is="row"></li>
            </ol>
        </table>
        <select>
            <option is="row"></option>
            <option is="row"></option>
            <option is="row"></option>
        </select> -->

        <!-- 知识点2 子组件当中定义data,data必须是一个返回对象的函数。只有在根组件实例中,data才可以是一个对象-->
        <!-- <table>
            <tbody>
                <tr is="row"></tr>
                <tr is="row"></tr>
                <tr is="row"></tr>
            </tbody>
        </table> -->

        <!-- 知识点3 ref -->
        <!-- ref 获取dom或实例引用的语法 -->
        <!-- ref在dom标签上,则this.$refs.name 获取的是这个dom元素 -->
        <!-- ref在组件上,则this.$refs.name 获取的是这个组件的引用,即这个vue子组件实例的引用 -->
        <!-- ref在组件的知识点见知识点4 -->
        <!-- <div
            ref='hello'
            @click="handleClick"
        >
            hello world
        </div> -->

        <!-- 知识点4 -->
        <!-- 实现一个计算器求和的功能 -->
        <!-- ref在组件上,在父组件用this.$refs.name 获取的是这个子组件的引用,即这个vue子组件实例的引用 -->        
        <counter ref="one" @change="handleChange"></counter>
        <counter ref="two" @change="handleChange"></counter>
        <div>{{total}}</div>
    </div>

    <script>
        // 知识点1
        // Vue.component('row', {
        //     template: '<tr><td>this is a row</td></tr>'
        // })

        // 知识点2 data
        // Vue.component('row', {
            // 下面这样错误,只有根组件的data才可以是对象形式
            // data:{
            //     content:"this is a row"
            // },
            // 子组件的data应该是function形式 这个函数返回一个对象
            // 这样设置的目的是每一个子组件<row>是独享一套数据,而不是和其他<row>共享同一套数据,这样就不会出现不同子组件之间数据互相影响的情况
        //     data:function(){
        //         return {
        //             content:"this is a row"
        //         }
        //     },
        //     template: '<tr><td>{{content}}</td></tr>'
        // })
        
        // 知识点3 ref
        // vue不建议我们直接操作dom,而是希望通过操作数据来实现对dom的操作
        // 但必要情况下,我们需要直接操作dom,这就需要用到ref
        // var vm = new Vue({
        //     el: '#root',
        //     methods:{
        //         handleClick:function(){
                    // alert('click')
                    // this.$refs 指的是整个vue实例中所有的引用
                    // this.$refs.hello 指的是ref名为hello的dom元素
        //             console.log(this.$refs.hello);
        //             console.log(this.$refs.hello.innerHTML);
        //         }
        //     }
        // })

        // 知识点4
        Vue.component('counter',{
            template:'<div @click="handleClick">{{number}}</div>',
            data:function(){
                return {
                    number:0
                }
            },
            methods:{
                handleClick:function(){
                    this.number++;
                    this.$emit('change')
                }
            }
        })
        // 注意computed不能监听refs的变化,只能放在methods当中
        var vm=new Vue({
            el:'#root',
            data:{
                total:0
            },
            methods:{
                handleChange:function(){
                    // 为了父组件能够对两个子组件的数据进行求和,这时候需要用到ref方法
                    // console.log(this.$refs.one.number);
                    this.total=this.$refs.one.number+this.$refs.two.number
                }
            }
        })
    </script>
</body>

</html>

十六、父传子

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>父传子</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- 父传子 props 单项数据流-->
        <!-- :count="0" 0是数字 "0"是js表达式 -->
        <!-- count="0" 0是字符串 -->
        <counter :count="1"></counter>
        <counter :count="2"></counter>
    </div>

    <script>
        var counter = {
            props: ['count'],
            data: function () {
                return {
                    number: this.count
                }
            },
            template: "<div @click='handleClick'>{{number}}</div>",
            methods: {
                handleClick: function () {
                    // 下面这样直接操作父组件传过来的数据,虽然可以操作成功,但是控制台会报警告说不要这样操作
                    // 单向数据流:子组件只能接收使用父组件传过来的数据,而不可以进行操作
                    // 因为万一传过来的不是值数据而是引用型数据的话,子组件再修改数据,会引起混乱
                    this.number++;
                }
            }
        }
        var app = new Vue({
            el: '#root',
            // 注意局部组件才需要注册
            components: {
                counter: counter
            }
        })
    </script>
</body>

</html>

十七、子传父

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>子传父</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- 子监听父的 -->
        <!-- 监听事件 @加上事件名 例如 @inc= -->
        <counter :count="3" @inc="handleInc"></counter>
        <counter :count="2" @inc="handleInc"></counter>
        <div>{{total}}</div>
    </div>

    <script>
        var counter = {
            props: ['count'],
            data: function () {
                return {
                    number: this.count
                }
            },
            template: "<div @click='handleClick'>{{number}}</div>",
            methods: {
                handleClick: function () {
                    this.number = this.number + 2;
                    // 子传父,通过触发事件并且携带参数的方式
                    // 子传父 发送事件名,后面为带过去的数据
                    this.$emit('inc', 2)
                }
            }
        }
        var app = new Vue({
            el: '#root',
            data: {
                total: 5
            },
            components: {
                counter: counter
            },
            methods: {
                handleInc: function (step) {
                    this.total += step;
                }
            }
        })
    </script>
</body>

</html>

十八、组件参数校验和非props

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件参数校验和非props</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <child content="hello world"></child>
        <child content="hell"></child>
        <!-- 下面为Number,不会通过String类型的校验 控制台会报错 -->
        <!-- <child :content="123"></child> -->
    </div>

    <script>
        // 组件参数校验
        // 指的是子组件对父组件传递过来的content进行一些校验,比如必须要是字符串,如果是别的我不要
        // 要进行参数校验的话,就不能是props:['content']这种数组格式,应该写成对象,如下

        // props特性:父传子,子要接(一个属性),即子在props内进行了声明  父子组件有一个对应关系
        // 非props特性:父传子,子不接(一个属性),即子没有在props内进行声明

        // props特性的特点:
        // (1)传递的这个属性不会出现在最终渲染的标签上
        // (2)子可以通过插值表达式或者this.的方式获取父传过来的属性值

        // 非props特性的特点:
        // (1)传递的这个属性 会展示在子组件最外面的dom标签的html之中,即是attribute而不是property
        // (2)子无法获取父组件的这个内容,没法用

        Vue.component('child', {
            // 校验1
            // props: {
            //     content: Number
            // },
            // 校验2          
            // props: {
            //     content: [Object, String]
            // },
            // 校验3            
            // props: {
            //     content: {
            //         type: Number
            //     }
            // },
            // 校验4
            // props: {
            //     content: {
            //         type: String,
            // required:false, //true指的是这个值是必传的,就会报错。false则是可传可不传
            // default:'default value' //required:false 时如果没传则会用这个默认值
            // 更复杂的校验项
            // validator: function (value) {
            // 要求传过来的值的长度要大于5,否则报错
            //             return (value.length > 5)
            //         }
            //     }
            // },
            template: "<div>{{content}}</div>"
        })
        var app = new Vue({
            el: '#root'
        })
    </script>
</body>

</html>

十九、给组件绑定原生事件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>给组件绑定原生事件</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- @click.native -->
        <!-- 加了native之后,此时监听的是原生事件,而不是组件的自定义事件 -->
        <!-- 给组件绑定原生事件:在后面加上 .native修饰符即可 -->
        <child @click.native="handleClick"></child>
    </div>

    <script>
        Vue.component('child', {
            template: '<div>Child</div>',
            // template: '<div @click="handleClick">Child</div>',
            // methods: {
            //     handleClick: function () {
            //         // alert('child click');
            //         this.$emit('click');
            //     }
            // }
        })
        var app = new Vue({
            el: '#root',
            methods: {
                handleClick: function () {
                    alert('click')
                }
            }
        })
    </script>
</body>

</html>

二十、非父子组件传值(Bus/总线/发布订阅模式/观察者模式)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>非父子组件传值(Bus/总线/发布订阅模式/观察者模式)</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <child content="Dell"></child>
        <child content="Lee"></child>
    </div>

    <script>
        Vue.prototype.bus = new Vue();
        // 这样可以使后面创建的每个组件或者每个vue实例都具有bus这个属性
        // 并且这个vue属性将指向同一个vue实例
        // 这个vue实例存在的意义

        Vue.component('child', {
            data: function () {
                return {
                    selfContent: this.content
                }
            },
            props: {
                content: String
            },
            template: "<div @click='handleClick'>{{selfContent}}</div>",
            methods: {
                handleClick: function () {
                    // console.log(this.content);
                    this.bus.$emit('change', this.selfContent);
                }
            },
            // this.bus是一个vue实例,所以具有emit和on方法
            mounted: function () {
                this.bus.$on('change', (msg) => {
                    // alert(msg)
                    this.selfContent = msg;
                })
            }
        })

        var app = new Vue({
            el: '#root'
        })
    </script>
</body>

</html>

二十一、vue插槽(slot)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue插槽(slot)</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- 旧的方案 props -->
        <!-- <child content="<p>Dell</p>"></child> -->
        <!-- 新的方案 slot -->
        <!-- <child><p>Dell</p></child>
        <child></child> -->
        <!-- 具名插槽 slot -->
        <body-content>
            <div class="header" slot="header">header</div>
            <div class="footer" slot="footer">footer</div>
        </body-content>
    </div>

    <script>
        // 插槽的使用场景
        // 需求:div标签里面不仅要展示p标签,还需要展示一个标签,但是这个标签不是由子组件决定的,是由父组件传递过来的
        // 1.按以前的解决方法:props
        // 缺点1:
        // 这样会在p标签外多一层div标签
        // <div v-html="this.content"></div>
        // 这个模板占位符不管用
        // <template v-html="this.content"></template>
        // 缺点2:
        // 一旦父组件传递过来的内容变多了,就会变得阅读性困难

        // 单插槽
        // 2.这时候我们需要用新的解决方案:插槽 slot
        // 即如何在父子组件之间优雅的传递dom
        // 在子组件当中直接用<slot></slot> 即可把父组件传递的展示出来
        // 在子组件当中直接用<slot>默认内容</slot>,若父组件不传递内容过来便展示默认内容,若传递则展示父组件的
        // 多插槽 具名插槽
        // Vue.component('child',{
        //     props:['content'],
        //     template:`<div>
        //                     <p>hello</p>
        //                     <slot>默认内容</slot>
        //               </div>`
        // })
        
        // 具名插槽
        Vue.component('body-content',{
            props:['content'],
            template:`<div>
                            <slot name="header"></slot>
                            <p>hello</p>
                            <slot name="footer"></slot>
                      </div>`
        })
        var app = new Vue({
            el: '#root'
        })
    </script>
</body>

</html>

二十二、作用域插槽

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>作用域插槽</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <child>
            <template slot-scope="props1">
                <li>{{props1.item}}--hello</li>
            </template>
        </child>
    </div>

    <script>
        Vue.component('child', {
            data: function () {
                return {
                    list: [1, 2, 3, 4]
                }
            },
            template: `<div>
                        <ul>
                            <slot v-for="item of list"
                            :item=item>
                            </slot>
                        </ul>
                        </div>`
        })
        var app = new Vue({
            el: '#root'
        })
    </script>
</body>

</html>

二十三、动态组件 v-once

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>动态组件</title>
    <script src='./vue.js'></script>
</head>

<body>
    <div id="root">
        <!-- <component></component>就是vue里的动态组件 -->
        <!-- 动态组件定义:根据is值的变化动态的加载不同的组件 -->
        <component :is="type"></component>
        <!-- 原始组件 -->
        <child-one v-if="type==='child-one'"></child-one>
        <child-two v-if="type==='child-two'"></child-two>
        <button @click="handleClick">change</button>
        <!-- v-once 内部内容只渲染一次,即使内部内容依赖数据发生变化也不重新渲染 -->
    </div>

    <script>
        Vue.component('child-one', {
            template: "<div>child-one</div>"
        })
        Vue.component('child-two', {
            template: "<div>child-two</div>"
        })
        var app = new Vue({
            el: '#root',
            data: {
                type: "child-one"
            },
            methods: {
                handleClick: function () {
                    this.type = (this.type === 'child-one' ? 'child-two' : 'child-one')
                }
            }
        })
    </script>
</body>

</html>

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值