局部组件与全局组件

局部组件

// 这是一个局部组件
const App = {
    template: `
        <div>
            <h3>{{msg}}</h3>    
            <button @click="handleClick">按钮</button>
        </div>
    `,
    // 组件中的data必须是一个函数,并返回一个对象,避免数据冲突
    data() {
        return {
            msg: 'App组件'
        }
    },
    methods: {
        handleClick() {
            this.msg = 'App组件Changed'
        }
    }
}
new Vue({
    el: "#app",
    data: {
    },
    components: {
       // 在此处挂载子组件
       // 等价于App:App
       App
    }
})

全局组件

使用Vue.component 创建的组件是全局注册的,它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中

<body>
    <div id="app">
        <App></App>
        <!-- 这里使用MyHeader会报错 -->
        <my-header></my-header> 	
    </div>
</body>
<script src="./vue.js"></script>
<script>
    // 全局组件
    Vue.component('MyHeader', {
        template: `
            <div>
                导航组件
            </div>
        `
    })
    // 此处使用MyHeader可以正常运行
    const App = {
        template: `
            <div>
                <MyHeader></MyHeader>
                <h3>{{msg}}</h3>    
                <button @click="handleClick">按钮</button>
            </div>
     `,
        data() {
            return {
                msg: 'App组件'
            }
        },
        methods: {
            handleClick() {
                this.msg = 'App组件Changed'
            }
        }
    }
    new Vue({
        el: "#app",
        data: {
        },
        // 全局组件不需要在components中挂载,直接使用
        components: {
            App
        }
    })
</script>

组件通信

父组件向子组件传值

  1. 在子组件中声明props接收父组件传递的值
  2. 在父组件中绑定自定义的属性
<script>
    Vue.component('Child', {
        template: `
            <div>
                <h3>子组件</h3>
                <h4>{{ childData }}</h4>
            </div>
        `,
        props: ['childData']
    })
    const App = {
        template: `
            <div>
                <Child :childData = 'msg'></Child>
            </div>
     `,
        data() {
            return {
                msg: '父组件传递的值'
            }
        },
        methods: {}
    }
</script>

子组件向父组件传值

  1. 在父组件中 子组件上绑定自定义事件
  2. 在子组件中 触发原生的事件,在事件函数中通过this.$emit触发自定义的事件
<script>
    Vue.component('Child', {
        template: `
            <div>
                <h3>子组件</h3>
                <input type="text" @input="handleInput"/>
            </div>
        `,
        methods: {
            handleInput(e) {
                this.$emit('childSendMsg', e.target.value);
            }
        }
    })
    const App = {
        template: `
            <div>
                <Child @childSendMsg = 'handleGetChildMsg'></Child>
                <h3>{{childSendData}}</h3>
            </div>
     `,
        data() {
            return {
                childSendData: ''
            }
        },
        methods: {
            handleGetChildMsg(msg) {
                this.childSendData = msg
            }
        }
    }
</script>

平行组件通信-中央事件总线

  1. 新建一个空的Vue实例作为中央事件总线
  2. 在组件B创建的钩子函数中添加监听事件
  3. 在组件A中触发事件
<script>
    // 新建一个bus Vue实例对象
    const bus = new Vue();
    Vue.component('A', {
        template: `
            <div>
                <button @click="handleClick">加入购物车</button>
            </div>
        `,
        methods: {
            handleClick() {
                bus.$emit('add', 1);
            }
        }
    })
    Vue.component('B', {
        template: `
            <div>
                <h4>商品数量:{{ count }}</h4>
            </div>
        `,
        data() {
            return {
                count: 0
            }
        },
        created() {
            // 用bus而不是this,this指向当前组件
            bus.$on('add', n => {
                this.count += n;
            })
        },
        // 最好在组件销毁前,清除事件监听
        beforeDestroy() {
            bus.$off('add');
        }
    })
    const App = {
        template: `
            <div>
                <A></A>
                <B></B>
            </div>
     `
    }
</script>

provide与inject

  1. 在父组件中使用provide提供变量
  2. 在子组件中通过inject来注入变量,无论组件嵌套多深
<script>
    // A组件引入了B组件
    Vue.component('A', {
        template: `
            <div>
                <B></B>
            </div>
        `
    })
	// B组件通过inject获取了App组件的数据
    Vue.component('B', {
        template: `
            <div>
                <h3>{{msg}}</h3>
            </div>
        `,
        inject: ['msg']
    })
	// App 组件引入了A组件,使用provide提供了数据
    const App = {
        template: `
            <div>
                <A></A>
            </div>
     `,
        provide() {
            return {
                msg: 'APP组件数据'
            }
        }
    }
</script>

$parent与$children

通过this.$parent获取父组件

通过this.$children获取子组件数组

异步组件加载

以工厂函数的方式引入组件

组件文件 Test.js

export default  {
    data() {
        return {
            msg: '子组件'
        }
    },
    template: `
		<h3>{{msg}}</h3>
	`
}
<script type='module'>
    const App = {
        template: `
            <div>
                <Test v-if="isShow"></Test>
			   <button @click="asyncLoad">异步加载</button>
            </div>
     `,
        data() {
            return {
                isShow: false
            }
        }
        components: {
            Test: ()=>import('./Test.js') // 使用import引入
        },
        methods: {
            asyncLoad() {
                this.isShow = true;
            }
        }
    }
</script>

当点击按钮时,才会加载Test组件,而不是立即加载

对象变更检测

Vue不能检测对象属性的添加和删除

解决方法:

  • // Vue.$set(object, key, value)添加响应式属性
    this.$set(this.user, age, 20)
    
    
    - ```javascript
      this.user = Object.assign({}, this.user, {
          age: 20,
          phone: 123455
      })

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Vue插槽 上一篇
ES6中Promise与async的使用 下一篇