zoukankan      html  css  js  c++  java
  • vue第六单元(vue的实例和组件-vue实例的相关属性和方法-解释vue的原理-创建vue的组件)

    第六单元(vue的实例和组件-vue实例的相关属性和方法-解释vue的原理-创建vue的组件)

    #课程目标

    1. 掌握vue实例的相关属性和方法的含义和使用
    2. 了解vue的数据响应原理
    3. 熟悉创建组件,了解全局组件与局部组件的区别,掌握组件的相关注意事项

    #知识点

    #1.vue实例的相关属性和方法ß

    #1.1 属性

    Vue实例就是通过new Vue()得到的对象。 我们可以在先在控制台中打印一下vue的实例,如图:

    • app.$data 对应组件中data的值
    • app.$props 对应组件中props的值
    • app.$el vue实例挂载到的节点
    • app.$options 用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处
    • app.$parent 父实例,如果当前实例有的话。
    • app.$root 当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
    • app.$children <item><div></div></item> item的$children就是div
    • app.$slots 用来访问被插槽分发的内容
    • app.$scopedSlots 用来访问作用域插槽
    • app.$refs 一个对象,持有注册过 ref 特性 的所有 DOM 元素和组件实例。(用于所有添加过ref属性的元素)
    • app.$isServer 当前 Vue 实例是否运行于服务器
    • app.$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。
    • app.$listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

    在这里主要看这4个属性:

    • app.$el ===> vue实例挂载到的节点
    • app.$data ===> 对应组件中data的值
    • app.$options ===> 用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处
    • app.$refs ===> 用于所有添加过ref属性的元素

    app.$options方法实例:

    var app = new Vue({
            el: "#app",
            data:{
                msg:"hello vue!"
            },
            name:"xiaoming",
            age:23,
            showMe:function(){
                console.log("自定义showMe方法");
            }
        })
        console.log(app.$el);    // 获得了el的dom对象
        console.log(app.$data);  // 获得了data对象
        console.log(app.$options);   // 获得了自定义的属性对象
        console.log(app.$options.name);  // 获得了自定义的name,值为:xiaoming
        app.$options.showMe();  // 获取了自定义的show方法,并执行值为:自定义showMe方法
    
     

    app.$refs方法实例:

    <div id="app">
        <div class="div1" ref="divDom"></div>
        <p class="p1" ref="pDom"></p>
    </div>
    
    var app = new Vue({
        el: "#app",
        data:{
    
        }
    })
    console.log(app.$refs)   // 获取到了所有带有 ref的dom标签
    console.log(app.$refs.pDom) // 获取到了带有ref属性并且值为pDom的标签
    console.log(app.$refs.divDom) // 获取到了带有ref属性并且值为divDom的标签
    
    // 可以这样设置
    app.$refs.pDom.style.color = "pink";
    
     
    #1.2方法

    而vue实例中的方法,可以展开__proto__对象,如图,可以看见:

    其中,以下几个就是vue实例中的方法($emit,$on,$off,等等的方法之后课程再介绍):

    • app.$mount() 手动挂载vue实例
    • app.$destroy() 用于销毁vue实例
    • app.$nextTick(callback) 用于数据更改,dom更新完成后执行
    • app.set(object,key,value) 动态地为对象新增一个值,并且页面上的模版会实时地动态更新渲染值
    • app.$delete(object, key) 删除一个已有的属性,dom也会实时更新
    • app.$watch(data, callback(newValue,oldValue), [option]) 监视数据的变化

    app.$mount()===>手动挂载vue实例 有两种写法分别为:

    //第一种 
    var vm = new Vue({
         // el: "#app",      // 注释了挂载到dom对象
         data:{
         	msg:"hello vue!"
         }
     })
     vm.$mount("#app");   // 这样也可以挂载到dom对象
    
     
    //第二种
    var vm = new Vue({
         // el: "#app",      // 注释了挂载到dom对象
         data:{
         	msg:"hello vue!"
         }
     }).$mount("#app");      // 在实例最后调用$mount("需要挂载的dom");
    
     

    app.$nextTick(callback) ===> 用于数据更改,dom更新完成后执行

    var vm = new Vue({
        // el: "#app",      // 注释了挂载到dom对象
        data:{
        	msg:"hello vue!"
        }
    }).$mount("#app");
    
    vm.msg = "hello world!";      // 这里更改了数据
    
    // 这里获取DOM的内容为:hello vue!,因为dom数据还没更新完成
    console.log(vm.$refs.pDom.innerHTML);   
    
    // 这里获取DOM的内容为:hello world!,因为dom数据已经更新完成
    vm.$nextTick(function(){
    	console.log(vm.$refs.pDom.innerHTML);   
    });
    
     

    app.set(object,key,value) 实例用法

    <div class="box" id="app">
        <button @click="addFn">添加一个属性</button>
        {{user.name}}
        {{user.num}}
    </div>
    <script>
        var vm = new Vue({
            el: "#app",
            data:{
                user:{
                    name:"yang"
                }
            },
            methods:{
                addFn:function(){
                    //this.user.num = "9527";      // 页面上的模版无法渲染
                    //console.log(this.user);     // 能打印出来,但是也页面上的模版未渲染出来
                    // this.$set(this.user, "num", "9527");        // 页面上的模版渲染出来了值
                    Vue.set(this.user, "num", "9527")       //vm.$set 的全局写法
                }
            }
        })
    </script>
    
    
     

    app.$delete 实例用法

    <div class="box" id="app">
        <button @click="deleteFn">删除一个属性</button>
        {{user.name}}
    </div>
    <script>
        var vm = new Vue({
            el: "#app",
            data:{
                user:{
                    name:"yang"
                }
            },
            methods:{
                deleteFn: function(){
                    // vm.$delete(this.user, "name");      // 删除页面上已有的一个属性,dom也会实时更新
                    Vue.delete(this.user, "name");      // vm.$delete 全局写法
                }
            }
        })
    </script>
    
     

    vm.$watch(data, callback(newValue,oldValue), [option]) 实例用法

    <input type="text" v-model="msg">   // 绑定 vm.$watch 写法1
    {{msg}}
    
    <input type="text" v-model="id">    // 绑定 watch 写法2
    {{id}}
    
    <input type="text" v-model="user.name">    // 绑定 watch 写法2
    {{user.name}}
    
    var vm = new Vue({
        el:"#app",
        data:{
            msg:"hello vue!",
            id:"1001",
            user:{
            	name:"yang"
            }
        },
        /* watch:{     // 写法2:vue实例提供的一个选项 - 普通监视数据变化
        id:function(newValue, oldValue){
            	console.log("id更改之后的值"+ newValue +",id更改之前的值"+ oldValue);
            }
        } */
        watch:{     // 写法2:vue实例提供的一个选项 - 深度监视对象数据变化
            user:{
                    handler:function(newValue, oldValue){
                    console.log("user更改之后的值"+ newValue +",user更改之前的值"+ oldValue);
                },
                deep: true
            }
        }
    })
    
    // 写法1:vue实例提供的$watch方法 - 普通监视数据变化
    vm.$watch("msg",function(newValue, oldValue){      
    	console.log("msg更改之后的值"+ newValue +",msg更改之前的值"+ oldValue);
    })  
    
    // 写法1:vue实例提供的$watch方法 - 深度监视对象数据变化
    vm.$watch("user",function(newValue, oldValue){
        // 监视一个对象后,这里的newValue 和 oldValue将会指向同一指针,也就是指向了同一个值,更改前后值会一样
        console.log("user更改之后的值"+ newValue +",user更改之前的值"+ oldValue);    
        },{
        deep:true
    })
    
     

    #2.数据响应原理

    现代主流框架均使用一种数据=>视图的方式,封装了繁琐的dom操作,采用了声明式编程(Declarative Programming)替代了过去的类jquery的命令式编程(Imperative Programming)。

    这张图来自vue的官方文档,文档中讲:

    当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。

    这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

    每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

    总结为需要三个模块实现数据响应:

    • Observer:也就是vue官方文档第一段提到的使用Object.defineProperty监听数据变化,数据变化则触发setter,并通知订阅者Watcher。
    • Watcher:作为Observer和Compile之间通信的桥梁,在自身实例化时往属性订阅器(dep)里面添加自己,待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调。
    • Compile: 主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

    #3.vue 中的组件

    #3.1 组件的基本使用

    注册组件就是利用Vue.component()方法,先传入一个自定义组件的名字,然后传入这个组件的配置。这种方式创建的组件也叫做全局组件。

    Vue.component('mycomponent',{
        template: `<div>这是一个自定义全局组件</div>`,
        data () {
        return {
            message: 'hello world'
    		}
    	}
    })
    
     

    如上方式,就已经创建了一个自定义组件,然后就可以在Vue实例挂在的DOM元素中使用它。

    直接使用Vue.component()创建的组件,所有的Vue实例都可以使用。还可以在某个Vue实例中注册只有自己能使用的组件。也叫做局部组件。

    var app = new Vue({
            el: '#app',
            data: {
            },
            components: {
            'my-component': {
            template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>`,
            }
        }
    })
    
     

    具体对比实例:

    <div id="app1">
        <!—全局组件的使用-->
        <mycomponent></mycomponent>
        <!—局部组件的使用-->
        <my-component></my-component>
    </div>
    <div id="app2">
        <!—全局组件的使用-->
        <mycomponent></mycomponent>
        <!—局部组件的使用 此处的使用会报错-->
        <my-component></my-component>
    </div>
    <script>
    //定义全局组件  每个Vue实例中都能使用
    Vue.component('mycomponent',{
        template: `<div>这是一个自定义全局组件</div>`,
        data () {
        return {
            message: 'hello world'
            }
        } 
    })
    var app1 = new Vue({
        el: '#app1',
        data: {
        },
        components: {
        'my-component': {
                template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>`,
                }
        	}
        })
        var app2 = new Vue({
            el: '#app2',
            data: {
            }
    })
    </script>
    
     
    #3.2 template模板的要求

    注意:组件的模板只能有一个根元素。下面的情况是不允许的。

    template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>
    <button>hello</button>`,
    
     
    #3.3 组件中的data必须是函数

    可以看出,注册组件时传入的配置和创建Vue实例差不多,但也有不同,其中一个就是data属性必须是一个函数。

    这是因为如果像Vue实例那样,传入一个对象,由于JS中对象类型的变量实际上保存的是对象的引用,所以当存在多个这样的组件时,会共享数据,导致一个组件中数据的改变会引起其他组件数据的改变。

    而使用一个返回对象的函数,每次使用组件都会创建一个新的对象,这样就不会出现共享数据的问题来了。

    #3.4 关于DOM模板的解析

    当使用 DOM 作为模版时 (例如,将 el 选项挂载到一个已存在的元素上), 你会受到 HTML 的一些限制,因为 Vue 只有在浏览器解析和标准化 HTML 后才能获取模板内容。尤其像这些元素<ul>,<ol>,<table>,<select>限制了能被它包裹的元素,而一些像 <option> 这样的元素只能出现在某些其它元素内部。

    通俗点说,虽然 vue 渲染页面可以自定义,非常强大,但是他一定遵从遵循我们的浏览器正常解析,html 正常规范。

    在自定义组件中使用这些受限制的元素时会导致一些问题,例如:

    <table>
      <my-row>...</my-row>
    </table>
    
     

    自定义组件 被认为是无效的内容,因此在渲染的时候会导致错误。

    这时应使用特殊的 is 属性:

    <table>
      <tr is="my-row"></tr>
    </table>
    
     

    又或者是select这样的:

    <select>
    <my-component></my-component>
    </select>
    
     

    select 内置固定标签 option, 所以不能随意渲染

    也就是说,标准HTML中,一些元素中只能放置特定的子元素,另一些元素只能存在于特定的父元素中。比如table中不能放置div,tr的父元素不能div等。所以,当使用自定义标签时,标签名还是那些标签的名字,但是可以在标签的is属性中填写自定义组件的名字。

    #4.属性Props

    Vue组件通过props属性来声明一个自己的属性,然后父组件就可以往里面传递数据。

    Vue.component('mycomponent',{
        template: '<div>这是一个自定义组件,父组件传给我的内容是:{{myMessage}}</div>',
        props: ['myMessage'],
        data () {
        return {
            message: 'hello world'
            }
        }
    })
    
     

    然后调用该组件

    <div id="app">
    	<mycomponent my-message="hello"></mycomponent>
    </div>
    
     

    注意,由于HTML特性是不区分大小写的,所以传递属性值时,myMessage应该转换成 kebab-case (短横线隔开式)my-message="hello"。

    #授课思路

    #案例和作业

    使用vue完成一个tab切换

  • 相关阅读:
    Java-集合类汇总
    Java-ArrayList
    Java-ArrayList和Vector的区别
    Java-List
    Java-Stack
    Java-Vector
    Java-HashMap
    Java-EnumSet
    18校招借鉴
    spring的设计模式
  • 原文地址:https://www.cnblogs.com/yzy521/p/14132003.html
Copyright © 2011-2022 走看看