zoukankan      html  css  js  c++  java
  • Vue_组件化开发

    一、什么是组件

    ​ 其实突然出来的这个名词,会让您不知所以然,如果⼤家使⽤过bootstrap的⼀定会对这个名词不陌⽣,我们其实在很早的时候就接触这个名词。

    通常⼀个应⽤会以⼀颗嵌套的组件树的形式来阻⽌:

    123.PNG

    二、局部组件

    • ① 声子 Vue中 组件的名字首字母要大写,跟标签区分

    • ② 挂子 挂载哪个组件,这个组件就是我的父组件

    • ③ 用子

      注意:template中的模版一定要有一个根元素

      注意:在组件中这个data必须是一个函数,返回一个对象。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            // App组件
            // 1. 创建组件(声子)
            // 注意:在组件中这个data必须是一个函数,返回一个对象
            const App = {
                data() {
                    return {
                        msg: '我是App组件',
                    }
                },
                template: `
                   <div>
                        <h3>{{msg}}</h3>
                        <button @click = 'handleClick'>按钮</button>
                    </div>
                `,
                methods: {
                    handleClick() {
                        this.msg = '学习局部组件';
                    }
                }
            }
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    三、全局组件

    ​ 通过 Vue.component(组件名,{}) 创建全局组件,此时该全局组件可以在任意模板(template)中使用。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            //创建全局组件 第一个是组建名 第二个是配置
            // 只要创建了全局组件,可以在任意地方使用(template)
            Vue.component('Vheader',{
                template:`
                <div>
                    我是导航组件
                </div>
                `,
            })
    
            Vue.component('Vaside',{
                template:`
                <div>
                    我是侧边栏组件
                </div>
                `,
            })
    
            const Vcontent = {
                data(){
                    return {
    
                    }
                },
                template:`
                    <div>
                        我是内容组件
                    </div>
                `,
            }
    
            // App组件
            // 1. 创建组件
            // 注意:在组件中这个data必须是一个函数,返回一个对象
            const App = {
                data() {
                    return {
                        msg: '我是App组件',
                    }
                },
    
                components:{
                    Vcontent
                },
    
                template: `
                   <div>
                        <Vheader></Vheader>
                        <div>
                            <Vaside />
                            <Vcontent />
                        </div>
                   </div>
                `,
                methods: {
                    handleClick() {
                        this.msg = '学习局部组件';
                    }
                },
            }
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    四、组件传信

    4.1 组件的嵌套

    数据:单向数据流

    4.2 父子组件传值

    父传子:通过prop来进行通信

    步骤

    1、在子组件中声明props接收在父组件挂载的属性

    2、可以在子组件的template中任意使用

    3、在父组件中绑定自定义的属性,挂载数据属性

    <script>
    let Vheader = {
      data(){
         return{
         
         }
      },
      // 只要声明了父组件的属性,就可以使用
      props:['msg'],
      template:`
        <div>
           <h2>{{ msg }}</h2>
        </div>
      `
    }
    
    let App = {
       data(){
          return{
            text:"我是父组件的数据"
          } 
       },
       template:`
          <div id="a">
              <Vheader :msg = 'text'></Vherder>
          </div>
       `,
       methods:{},
       components:{
          Vheader
       }
     }
    </script>
    
    <Son :msg  = 'msg'>
    
    'msg'是当前父组件中的data的值
    :msg 是动态的绑定,就是绑定数据属性中的值
    
    <Son msg  = 'aaa'>
    静态,固定不变
    

    示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            // 创建全局组件,Child作为一个子组件
            Vue.component('Child', {
                template:`
                    <div>
                    <h3>我是一个子组件</h3>
                    <h4>{{childData}}</h4>
                    </div>
                `,
                props: ['childData']
            })
    
            // App作为父组件
            const App = {
                data() {
                    return {
                        msg: '我是父组件传进来的值',
                    }
                },
                template: `
                   <div>
                        
                       <Child :childData='msg'></Child>
                   </div>
                `,
            }
    
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    子往父传值 (自定义事件)

    1、在父组件中 子组件绑定自定义事件

    2、在子组件中,触发原生的事件,在事件函数中,通过this.$emit('方法名', 值)触发自定义的事件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            // 创建全局组件,Child作为一个子组件
            Vue.component('Child', {
                template:`
                    <div>
                    <h3>我是一个子组件</h3>
                    <h4>{{childData}}</h4>
                    <input type="text" @input='handleInput'/>
                    </div>
                `,
                props: ['childData'],
                methods: {
                    handleInput(e){
                        const val = e.target.value;
                        this.$emit('inputHandler', val);
                    }
                },
            })
    
            // App作为父组件
            const App = {
                data() {
                    return {
                        msg: '我是父组件传进来的值',
                        newVal: '',
                    }
                },
                methods: {
                    input(newVal){
                        this.newVal = newVal;
                    }
                },
                template: `
                   <div>
                        <div class='father'>
                            数据:{{newVal}}
                        </div>
                       <Child :childData='msg' @inputHandler='input'></Child>
                   </div>
                `,
            }
    
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    4.3 平行组件传值

    bus 公交车对象,创建中央事件总线

    绑定$on和$emit

    emit是触发事件

    let bus = new Vue();
    A=>B传值
    $emit('函数名', 值) => $on('函数名',()=>{})
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            const bus = new Vue();
            // 中央事件总线 bus
            Vue.component('B',{
                data(){
                    return {
                        count: 0
                    }
                },
                template:`
                    <div>{{count}}</div>
                `,
                //
                created(){
                    console.log(this)
                    // $on  绑定事件
                    bus.$on('add',(n)=>{
                        this.count+=n;
                    })
                },
            })
    
            Vue.component('A',{
                data(){
                    return {
                        
                    }
                },
                template:`
                    <div>
                        <button @click='handleClick'>加入购物车</button>
                    </div>
                `,
                methods:{
                    handleClick(){
                        console.log(this);
                        // 触发绑定的函数
                        // $emit  触发事件
                        bus.$emit('add',1);
                    }
                }
            })
    
            // App作为父组件
            const App = {
                data() {
                    return {
                       
                    }
                },
                template: `
                   <div>
                        <A></A>
                        <B></B>
                   </div>
                `,
            }
    
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    4.4 组件通信的其他方式 provide 和 inject

    父组件 provide来提供变量,然后在自组建中通过inject来注入变量,无论组件嵌套多深

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            const bus = new Vue();
            // 中央事件总线 bus
            Vue.component('B',{
                data(){
                    return {
                        count: 0
                    }
                },
                inject: ['msg'],
                created(){
                    console.log(this.msg);
                },
                template:`
                   <div>
                        {{msg}}
                    </div>
                `,
            
            })
    
            Vue.component('A',{
                data(){
                    return {
                        
                    }
                },
                created() {
                    // console.log(this.$parent.$parent);
                    // console.log(this.$children);
                },
                template:`
                    <div>
                        <B></B>
                    </div>
                `,
                
            })
    
            // App作为父组件
            const App = {
                data() {
                    return {
                       title: "老爹",
                    }
                },
                provide(){
                    return {
                        msg: '老爹的数据'
                    }
                },
                template: `
                   <div>
                        <A></A>
                   </div>
                `,
            }
    
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    4.5 组件化编码的基本流程

    • 拆分界面,抽取组件
    • 编写静态组件
    • 编写动态组件
      • 初始化数据,动态显示初始化界面
      • 实现与用户交互功能

    设计data

    • 类型: [{id:1, title: 'xxx', completed: false}]
    • 名称: todos
    • 位置:如果只是哪个组件用,交给他,如果是哪些组件用,交给共同的父组件

    关于状态数据的更新

    • data数据定义在哪个组件,更新数据的行为就定义在哪个组件
    • 如果子组件要更新父组件的数据,调用父组件的更新函数来更新父组件的数据
    • 一个组件接收属性数据不要直接修改,只是用来读取显示的

    4.6 组件间的通信

    1)组件通信的5种方式

    • props
    • vue的自定义事件
    • 全局事件总线
    • slot
    • vuex

    2)props

    • 父子组件通信的基本方式
    • 属性值的2大类型:
      • 一般/非函数: 父组件 --->子组件
      • 函数: 子组件 ---> 父组件

    五、生命周期

    什么是⽣命周期?
    每个 Vue 实例在被创建时都要经过⼀系列的初始化过程。 例如:从开始创建、初始化数据、编译模板、挂载Dom、数据变化时更新DOM、卸载等⼀系列过程。 我们称 这⼀系列的过程 就是Vue的⽣命周期。 通俗说就是Vue实例从创建到销毁的过程,就是⽣命周期。 同时在这个过程中也会运⾏⼀些叫做⽣命周期钩⼦的函数,这给了⽤户在不同阶段添加⾃⼰的代码的机会,利⽤各个钩⼦来完成我们的业务代码。

    322.jpg

    322.jpg

    beforeCreate

    ​ 实例初始化之后、创建实例之前的执⾏的钩⼦事件

    Vue.component('Test',{
    	data(){
    	return {
    	msg:'⼩⻢哥'
    	}
    	},
    	template:`
    	<div>
    	<h3>{{msg}}</h3>
    	</div>
    	`,
    	beforeCreate:function(){
    	// 组件创建之前
    	console.log(this.$data);//undefined
    
    	}
    })
    

    效果

    123.PNG

    ​ 创建实例之前,数据观察和事件配置都没好准备好。也就是数据 也没有、DOM也没⽣成

    created

    ​ 实例创建完成后执⾏的钩⼦

    created(){
              // 非常重要的事情,在此发送ajax,请求后端的数据
              console.log('组件创建完成',this.$data);
           },
    

    效果

    123.PNG

    ​ 实例创建完成后,我们能读取到数据data的值,但是DOM还没⽣ 成,可以在此时发起ajax

    beforeMount

    ​ 将编译完成的html挂载到对应的虚拟DOM时触发的钩⼦ 此时⻚⾯并 没有内容。 即此阶段解读为: 即将挂载

    beforeMount() {
           // 挂载数据到 DOM之前会调⽤,即将挂载
                    console.log('DOM挂载之前',document.getElementById('app'));
                },
    

    效果

    123.PNG

    mounted

    ​ 编译好的html挂载到⻚⾯完成后所执⾏的事件钩⼦函数

     mounted(){
                    // 发送ajax
                    console.log('DOM挂载完成',document.getElementById('app'));
                },
    

    效果

    123.PNG

    beforeUpdate 和 updated

    beforeUpdate() {
                    // 获取更新之前的DOM
                    console.log('更新之前的DOM', document.getElementById('app').innerHTML);
                },
                updated(){
                    // 获取最新的DOM
                    console.log('更新之后的DOM', document.getElementById('app').innerHTML);
                },
    

    效果

    123.PNG

    activated 和 deactivated

    ​ 当配合vue的内置组件 ⼀起使⽤的时候,才会调⽤下⾯此 ⽅法 组件的作⽤它可以缓存当前组件

    activated(){
                    console.log('组件被激活了');
                },
                deactivated() {
                    console.log('组件被停用了');
                },
    

    beforeDestroy 和 destroyed

    ​ 当⼦组件在v-if的条件切换时,该组价处于创建和销毁的状态

    beforeDestroy() {
                    console.log('销毁之前');
                },
                destroyed() {
                    console.log('销毁完成');
                },
    

    整体代码示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
        <div id="app">
            <!--3、使用子组件-->
            <App></App>
        </div>
    
        <script>
            /*
            beforeCreate
            created
            beforemount
            mounted
            beforeUpdate
            updated
            activated  激活
            deactivated  停用
            配合keep-alive
            beforeDestroy
            destroyed
            */
            Vue.component('Test',{
                data(){
                    return {
                        msg: '白开水'
                    }
                },
                methods: {
                    handleClick(){
                        this.msg = 'AAAA'
                    }
                },
                template:`
                    <div>
                        <button @click='handleClick'>改变你</button>
                        <h3>{{msg}}</h3>
                    </div>
                `,
                beforeCreate(){
                    console.log('组件创建之前',this.$data);
                },
                created(){
                    // 非常重要的事情,在此发送ajax,请求后端的数据
                    console.log('组件创建完成',this.$data);
                },
                beforeMount() {
                    // 即将挂载
                    console.log('DOM挂载之前',document.getElementById('app'));
                },
                mounted(){
                    // 发送ajax
                    console.log('DOM挂载完成',document.getElementById('app'));
                },
                beforeUpdate() {
                    // 获取更新之前的DOM
                    console.log('更新之前的DOM', document.getElementById('app').innerHTML);
                },
                updated(){
                    // 获取最新的DOM
                    console.log('更新之后的DOM', document.getElementById('app').innerHTML);
                },
                beforeDestroy() {
                    console.log('销毁之前');
                },
                destroyed() {
                    console.log('销毁完成');
                },
                activated(){
                    console.log('组件被激活了');
                },
                deactivated() {
                    console.log('组件被停用了');
                },
            })
    
    
            // 1. 创建组件
            const App = {
                data() {
                    return {
                        isShow: true
                    }
                },
    
                components:{
                },
                methods:{
                    clickHandler(){
                        this.isShow = !this.isShow;
                    }
                },
                template: `
                   <div>
                        <keep-alive>
                            <Test v-if='isShow'></Test>
                        </keep-alive>
                        <button @click='clickHandler'>改变组件生死</button>
                   </div>
                `,
            }
            new Vue({
                el: '#app',
                data: {
    
                },
                components:{
                    // 2. 挂载子组件
                    App
                }
    
            })
        </script>
    </body>
    </html>
    

    六、组件进阶

    6.1 动态组件

    ​ 有的时候,在不同组件之间进⾏动态切换是⾮常有⽤的,⽐如在⼀个多标 签的界⾯⾥

    const bus = new Vue();
    	Vue.component('TabLi', {
    	data() {
    	return {
    	}
    	},
    	methods: {
    	clickHandler(title) {
    	bus.$emit('handleChange', title);
    	}
    	},
    	props: ['tabTitles'],
    	template: `
    	<ul>
    		<li @click='clickHandler(title)' v-for='(title,i) in tabTitles' :key='i'>			{{title}}
    		</li>
    	</ul>
    	`
    	})
    	const Home = {
    	data() {
    	return {
    	isActive:false
    	}
    	},
    	methods: {
    	handleClick(){
    	this.isActive = true;
    	}
    	},
    	template: `<div @click='handleClick'
    :class='{active:isActive}'>Home Component</div>`
    	}
    	const Posts = {
    	data() {
    	return {
    	}
    	},
    	template: `<div>Posts Component</div>`
    	}
    	const Archive = {
    	data() {
    	return {
    	}
    	},
    	template: `<div>Archive Component</div>`
    	}
    	Vue.component('TabComp', {
    	data() {
    	return {
    	title: 'Home'
    	}
    	},
    	created() {
    	bus.$on('handleChange', (title) => {
    	this.title = title
    	})
    	},
    	template: `
    	<div class='content'>
    	<componet :is='title'></componet>
    	</div>
    	`,
    	components: {
    	Home,
    	Posts,
    	Archive
    	}
    	})
    
    	const App = {
    	data() {
    	return {
    	tabTitles: ['Home', 'Posts', 'Archive']
    	}
    	},
    	template: `
    	<div>
    	<TabLi :tabTitles='tabTitles'></TabLi>
    	<TabComp></TabComp>
    	</div>
    	`,
    	}
    	new Vue({
    	el: '#app',
    	data() {
    	return {
    	}
    	},
    	components: {
    	App,
    	}
    	})
    

    使⽤ is 特性来切换不同的组件当在这些组件之间切换的时候,有时候会想保持这些组件的状态,以避免 反复渲染导致的性能问题

    6.2 在动态组件上使⽤keep-alive

    <keep-alive>
        <componet :is='title'></componet>
    </keep-alive>
    

    6.3 异步组件

    ​ 在⼤型应⽤中,我们可能需要将应⽤分割成⼩⼀些的代码块,并且只 在需要的时候才从服务器加载⼀个模块。为了简化,Vue 允许你以⼀ 个⼯⼚函数的⽅式定义你的组件,这个⼯⼚函数会异步解析你的组件 定义。Vue 只有在这个组件需要被渲染的时候才会触发该⼯⼚函数, 且会把结果缓存起来供未来重渲染。例如:

    const App = {
    	data() {
    	return {
    	isShow:false
    	}
    	},
    	methods:{
    	asyncLoadTest(){
    	this.isShow = true;
    	}
    	},
    	template:`
    	<div>
    	<button @click='asyncLoadTest'>异步加载
    </button>
    	<test v-if='isShow'/>
    	</div>
    
    	`,
    	components:{
    	//异步加载组件
    	test:()=>import('./Test.js')
    	}
    	}
    	new Vue({
    	el:'#app',
    	data(){
    	return {
    
    	}
    	},
    	components:{
    	App
    	}
    	})
    

    6.4 获取DOM和⼦组件对象

    ​ 尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript ⾥直接 访问⼀个⼦组件。为了达到这个⽬的,你可以通过 ref 特性为这个 ⼦组件赋予⼀个 ID 引⽤。例如:

    const Test = {
    	template: `<div class='test'>我是测试组件</div>`
    	}
    	const App = {
    	data() {
    	return {
    
    	}
    	},
    	created() {
    	console.log(this.$refs.test); //undefined
    
    	},
    	mounted() {
    	// 如果是组件挂载了ref 获取是组件对象,如果是标签挂
    载了ref,则获取的是DOM元素
    	console.log(this.$refs.test);
    	console.log(this.$refs.btn);
    	// 加载⻚⾯ 让input⾃动获取焦点
    	this.$refs.input.focus();
    
    	},
    	components: {
    	Test
    	},
    	template: `
    	<div>
    	<button ref = 'btn'></button>
    	<input type="text" ref='input'>
    	<Test ref = 'test'></Test>
    	</div>
    	`
    	}
    	new Vue({
    	el: '#app',
    	data: {
    
    	},
    	components: {
    	App
    	}
    	})
    

    6.5 netTick的用法

    ​ 将回调延迟到下次 DOM 更新循环之后执⾏。在修改数据之后⽴即使 ⽤它,然后等待 DOM 更新

    ​ 有些事情你可能想不到,vue在更新DOM时是异步执⾏的.只要侦听到 数据变化,Vue将开启⼀个队列,并缓存在同⼀事件循环中发⽣的所有数 据变更.如果同⼀个wather被多次触发,只会被推⼊到队列中⼀次.这种 在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是⾮常重 要的。然后,在下⼀个的事件循环“tick”中,Vue 刷新队列并执⾏实际 (已去重的) ⼯作

    <div id="app">
    	<h3>{{message}}</h3>
    	</div>
    	<script src="./vue.js"></script>
    	<script>
    	const vm = new Vue({
    	el:'#app',
    	data:{
    	message:'123'
    	}
    	})
    	vm.message = 'new Message';//更新数据
    	console.log(vm.$el.textContent); //123
    	Vue.nextTick(()=>{
    	console.log(vm.$el.textContent); //new Message
    
    	})
    	</script>
    

    ​ 当你设置 vm.message = 'new Message' ,该组件不会⽴即重新渲染.当 刷新队列时,组件会在下⼀个事件循环'tick'中更新.多数情况我们不需 要关⼼这个过程,但是如果你想基于更新后的 DOM 状态来做点什 么,这就可能会有些棘⼿。虽然 Vue.js 通常⿎励开发⼈员使⽤“数据 驱动”的⽅式思考,避免直接接触 DOM,但是有时我们必须要这么 做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后⽴即使⽤ Vue.nextTick(callback) 。这样回调函数将在 DOM 更新完成后被调⽤。

    nextTick的应⽤有个需求:

    在⻚⾯拉取⼀个接⼝,这个接⼝返回⼀些数据,这些数据是这个 ⻚⾯的⼀个浮层组件要依赖的,然后我在接⼝⼀返回数据就展示 了这个浮层组件,展示的同时,上报⼀些数据给后台(这些数据 就是⽗组件从接⼝拿的),这个时候,神奇的事情发⽣了,虽然 我拿到数据了,但是浮层展现的时候,这些数据还未更新到组件 上去,上报失败

    const Pop = {
    	data() {
    	return {
    	isShow:false
    	}
    	},
    	template:`
    	<div v-show = 'isShow'>
    	{{name}}
    	</div>
    	`,
    	props:['name'],
    	methods: {
    	show(){
    	this.isShow = true;
    	alert(this.name);
    	}
    	},
    	}
    	const App = {
    	data() {
    	return {
    	name:''
    	}
    	},
    	created() {
    	// 模拟异步请求的数据
    	setTimeout(() => {
    	this.name = '⼩⻢哥',
    	this.$refs.pop.show();
    	}, 2000);
    	},
    	components:{
    	Pop
    	},
    	template: `<pop ref='pop' :name='name'></pop>`
    	}
    	const vm = new Vue({
    	el: '#app',
    	components: {
    	App
    	}
    	})
    

    完美解决

    created() {
    	// 模拟异步请求的数据
    	setTimeout(() => {
    	this.name = '⼩⻢哥',
    	this.$nextTick(()=>{
    	this.$refs.pop.show();
    	})
    	}, 2000);
    	},
    

    对象变更检测注意事项

    ​ 由于JavaScript的限制,Vue不能检测对象属性的添加和删除

    对于已经创建的实例,Vue不允许动态添加根级别的响应式属性.但是,可 以通过 Vue.set(object,key,value) ⽅法向嵌套独享添加响应式属性

    	<div id="app">
    	<h3>
    	{{user.name}}{{user.age}}
    	<button @click='handleAdd'>添加年龄</button>
    	</h3>
    	</div>
    	<script src="./vue.js"></script>
    	<script>
    	new Vue({
    	el:'#app',
    	data:{
    	user:{},
    	},
    	created() {
    	setTimeout(() => {
    	this.user = {
    	name:'张三'
    	}
    	}, 1250);
    	},
    	methods: {
    	handleAdd(){
    	console.log(this);
    	// ⽆响应式
    	// this.user.age = 20;
    	// 响应式的
    	this.$set(this.user,'age',20);
    	}
    	},
    	})
    	</script>
    
    this.$set(this.user,'age',20);//它只是全局Vue.set的别名
    

    如果想为已存在的对象赋值多个属性,可以使⽤ Object.assign()

    // ⼀次性响应式的添加多个属性
    	this.user = Object.assign({}, this.user, {
    	age: 20,
    	phone: '113131313'
    	})
    

    6.6 混⼊mixin偷懒

    ​ 混⼊(mixin)提供了⼀种⾮常灵活的⽅式,来分发Vue组件中的可复 ⽤功能.⼀个混⼊对象可以包含任意组件选项.

    ​ ⼀个混⼊对象可以包含任意组件选项。当组件使⽤混⼊对象时, 所有混⼊对象的选项将被“混合”进⼊该组件本身的选项。

    <div id="app">
    	{{msg}}
    	</div>
    	<script src="./vue.js"></script>
    	<script>
    	const myMixin = {
    	data(){
    	return {
    	msg:'123'
    	}
    	},
    	created() {
    	this.sayHello()
    	},
    	methods: {
    	sayHello(){
    	console.log('hello mixin')
    	}
    	},
    	}
    	new Vue({
    	el: '#app',
    	data(){
    	return {
    	msg:'⼩⻢哥'
    	}
    	},
    	mixins: [myMixin]
    	})
    

    mixin应用

    ​ 有⼀种很难常⻅的情况:有两个⾮常相似的组件,他们共享同样的基本 函数,并且他们之间也有⾜够的不同,这时你站在了⼀个⼗字路⼝:我是 把它拆分成两个不同的组件?还是只使⽤⼀个组件,创建⾜够的属性 来改变不同的情况。

    ​ 这些解决⽅案都不够完美:如果你拆分成两个组件,你就不得不冒着 如果功能变动你要在两个⽂件中更新它的⻛险,这违背了 DRY 前提。 另⼀⽅⾯,太多的属性会很快会变得混乱不堪,对维护者很不友好, 甚⾄是你⾃⼰,为了使⽤它,需要理解⼀⼤段上下⽂,这会让你感到 失望。

    ​ 使⽤混合。Vue 中的混合对编写函数式⻛格的代码很有⽤,因为函数 式编程就是通过减少移动的部分让代码更好理解。混合允许你封装⼀ 块在应⽤的其他组件中都可以使⽤的函数。如果被正确的使⽤,他们 不会改变函数作⽤域外部的任何东⻄,所以多次执⾏,只要是同样的 输⼊你总是能得到⼀样的值。这真的很强⼤。

    ​ 我们有⼀对不同的组件,他们的作⽤是切换⼀个状态布尔值,⼀个模态框 和⼀个提示框.这些提示框和模态框除了在功能,没有其它共同点:它们 看起来不⼀样,⽤法不⼀样,但是逻辑⼀样

    <div id="app">
    	<App></App>
    	</div>
    	<script src="./vue.js"></script>
    	<script>
    	// 全局混⼊ 要格外⼩⼼ 每次实例创建 都会调⽤
    	Vue.mixin({
    	created(){
    	console.log('hello from mixin!!');
    	}
    	})
    	// 抽离
    	const toggleShow = {
    	data() {
    	return {
    	isShow: false
    	}
    	},
    	methods: {
    	toggleShow() {
    	this.isShow = !this.isShow
    	}
    	}
    	}
    	const Modal = {
    	template: `<div v-if='isShow'><h3>模态框组件
    </h3></div>`,
    	data() {
    	return {
    	}
    	},
    	mixins:[toggleShow]
    	}
    	const ToolTip = {
    	data() {
    	return {
    	}
    	},
    	template: `<div v-if='isShow'><h3>提示组件</h3>
    </div>`,
    	mixins:[toggleShow]
    	}
    	const App = {	data() {
    	return {
    	}
    	},
    	template: `
    	<div>
    	<button @click='handleModel'>模态框
    </button>
    	<button @click='handleToolTip'>提示框
    </button>
    	<Modal ref='modal'></Modal>
    	<ToolTip ref="toolTip"></ToolTip>
    	</div>
    	`,
    	components: {
    	Modal,
    	ToolTip
    	},
    	methods: {
    	handleModel() {
    	this.$refs.modal.toggleShow()
    	},
    	handleToolTip() {
    	this.$refs.toolTip.toggleShow()
    	}
    	},
    	}
    	new Vue({
    	el: '#app',
    	data: {},
    	components: {
    	App
    	},
    
    	})
    
  • 相关阅读:
    2019年3月6日 980. Unique Paths III
    2019年3月05日 961. N-Repeated Element in Size 2N Array
    2019年3月4日 701. Insert into a Binary Search Tree
    2019年3月1日 804. Unique Morse Code Words
    2019年2月28日 654. Maximum Binary Tree
    2019年2月26日 Unique Email Addresses、To Lower Case、Encode and Decode TinyURL
    Nexus Repository Manager 3 远程命令执行漏洞(CVE-2020-10199)复现
    常见的Web源码泄漏漏洞及其利用
    Nmap-脚本检测CVE漏洞
    Vulnhub-dpwwn-01靶机过关记录
  • 原文地址:https://www.cnblogs.com/jiaxiaozia/p/13774295.html
Copyright © 2011-2022 走看看