03 Vue组件化开发

1. 组件化开发思想

1.1 组件化思想

  • 标准
  • 分治
  • 重用
  • 组合

1.2 组件化规范: Web Components##

并不是所有浏览器都支持这个规范

  • 我们希望尽可能多的重用代码
  • 自定义组件的方式不太容易(html、css和js)
  • 多次使用组件可能导致冲突

Web Components 通过创建封装好功能的定制元素解决上述问题

官网:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components

Vue部分实现了上述规范

2. 组件注册

2.1 全局组件注册语法

Vue.component(组件名称, {
	data: 组件数据,
	template: 组件模板内容
})

演示

// 注册一个名为 button-counter 的新组件 Vue.component('button-counter', {
data: function () {
	return {
		count: 0
	}
}, 
template: '<button v-on:click="count++">点击了{{ count }}次.</button>'
 })

2.2 组件用法

<div id="app">
	<button-counter></button-counter>
</div>
// 组件数据是独立的
<div id="app">
	<button-counter></button-counter>
	<button-counter></button-counter>
	<button-counter></button-counter>
</div>

2.3 组件注册注意事项

1.data必须是一个函数

2.组件模板内容必须是单个跟元素

3.组件模板内容可以是模板字符串 ⚫

  • 模板字符串需要浏览器提供支持(ES6语法)

4.组件命名方式

  • 短横线方式

      Vue.component('my-component', { /* ... */ })
    
  • 驼峰方式

      Vue.component('MyComponent', { /* ... */ })
    

2.4 局部组件注册

局部组件只能在注册他的父组件中使用

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
	el: '#app'
	components: {
		'component-a': ComponentA,
		'component-b': ComponentB,
		'component-c': ComponentC,
		}
})

3. 组件间数据交互

3.1 父组件向子组件传值

1.组件内部通过props接收传递过来的值

Vue.component(‘menu-item', {
	props: ['title'],
	template: '<div>{{ title }}</div>'
})

2.父组件通过属性将值传递给子组件

<menu-item title="来自父组件的数据"></menu-item> 
<menu-item :title="title"></menu-item>

3.props属性名规则

  • 在props中使用驼峰形式,模板中需要使用短横线的形式

  • 字符串形式的模板中没有这个限制

    Vue.component(‘menu-item', {
    // 在 JavaScript 中是驼峰式的
    props: [‘menuTitle'],
    template: '

    {{ menuTitle }}
    '
    })
    <!– 在html中是短横线方式的 -->
    <menu-item menu-title=“nihao">

4.props属性值类型

  • 字符串 String
  • 数值 Number 不绑定是字符类型
  • 布尔值 Boolean 不绑定是字符类型
  • 数组 Array
  • 对象 Object

演示

<body>
    <div id="app">
        <div>{{pmsg}}</div>
        <menu-item :pstr="pstr" :pnum="12" :pboo=true :parr="parr" :pobj="pobj"></menu-item>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        // 父组件向子组件传值
        Vue.component('menu-item', {
            props: ["pstr", "pnum", "pboo", "parr", "pobj"],
            template: `
                <div>
                    <div>{{typeof pstr}}</div>
                    <div>{{12 + pnum}}</div>
                    <div>{{typeof pboo}}</div>
                    <ul>
                       <li :key='index' v-for='(item,index) in parr'> {{item}}</li>
                    </ul>
                    <div><span>{{pobj.name}}</span></div>
                    <div><span>{{pobj.age}}</span></div>

                </div>
            `
        })

        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件中内容',
                pstr: 'hello',
                parr: ['apple', 'orange'],
                pobj: {
                    age: 18,
                    name: "水井"
                }
            }
        })
    </script>

</body>

4.2 子组件向父组件传值

props传递数据原则:单向数据流

1.子组件通过自定义事件向父组件传递信息

<button v-on:click='$emit("enlarge-text") '>扩大字体</button>

2.父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>

3.子组件通过自定义事件向父组件传递信息

<button v-on:click='$emit("enlarge-text", 0.1) '>扩大字体</button>

4.父组件监听子组件的事件

<menu-item v-on:enlarge-text='fontSize += $event'></menu-item>
// $event是固定的 

4.3 兄弟组件间传值

1.单独的事件中心管理组件间的通信

var eventHub = new Vue()

2.监听事件与销毁事件

eventHub.$on('add-todo', addTodo)
eventHub.$off('add-todo')

3.触发事件

eventHub.$emit(‘add-todo', id)

5. 组件插槽

5.1 组件插槽的作用

父组件向子组件传递内容(模板内容)

组件插槽固定名称 slot

5.2 组件插槽基本用法

1.插槽位置

Vue.component('alert-box', {
	template: `
		<div class="demo-alert-box">
			<strong>Error!</strong>
			<slot></slot>
		</div>
	`
})

2.插槽内容

<alert-box>Something bad happened.</alert-box>

5.3 具名插槽用法

1.插槽定义

<div class="container">
	<header>
		<slot name="header"></slot>
	</header>
	<main>
		<slot></slot>
	</main>
	<footer>
		<slot name="footer"></slot>
	</footer>
</div>

2.插槽内容

<base-layout> 
	<h1 slot="header">标题内容</h1>
	<p>主要内容1</p> 
	<p>主要内容2</p>
	<p slot="footer">底部内容</p> 
</base-layout>

演示

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 第一种写法 -->
        <alert-box>
            <p slot="header">标题信息</p>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot="footer">底部信息</p>
        </alert-box>

        <!-- 第二种写法 -->
        <alert-box>
            <template slot="header">
                <p>标题信息1</p>
                <p>标题信息2</p>
            </template>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <template slot="footer">
                <p>底部信息1</p>
                <p>底部信息2</p>
            </template>
        </alert-box>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        //   组件插槽:父组件向子组件传递内容
        Vue.component('alert-box', {
            template: `
        <div>
          <header><slot name="header"></slot></header>
          <main><slot></slot></main>
          <footer><slot name="footer"></slot></footer>         
        </div>
      `
        });
        var vm = new Vue({
            el: '#app',
            data: {

            }
        });
    </script>
</body>

</html>

5.4 作用域插槽

  • 应用场景:父组件对子组件的内容进行加工处理

1.插槽定义

<ul>
	<li v-for= "item in list" v-bind:key= "item.id" >
		<slot v-bind:item="item">
			{{item.name}}
		</slot>
	</li>
</ul>

2.插槽内容

<fruit-list v-bind:list= "list">
	<template slot-scope="slotProps">
		<strong v-if="slotProps.item.current">
			{{ slotProps.item.text }}
		</strong>
	</template>
</fruit-list>
posted @ 2020-07-15 10:44  xujing123  阅读(163)  评论(0编辑  收藏  举报