Vue组件化开发

  • 组件化开发思想
  • 组件祖册
  • Vue调试工具用法
  • 组件间数据交互
  • 组件插槽
  • 基于组件的案例

组件化的开发思想

编程中的组件化开发思想

一个组件就是一个功能,多个组件组成一个完整的APP,抽取一个组件并不会影响其它组件的运行。

image.png

组件化规范: Web Components

官网:https://developer.mozilla.org...

组件的注册

组件的注册
image.png
image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue组件的使用</title>
</head>

<body>
    <div id="app">
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    Vue.component('button-count', {
        data() {
            return {
                count: '0',
            }
        },
        template: `<button @click='count++'>点击{{count}}次</button>`


    })
    let vm = new Vue({
        el: "#app",
        data: {

        }

    })
</script>

</html>

image

Vue组件注册之注意事项

注意事项

  • dta必须是一个函数
  • 组件模板内容必须是单个根元素
  • 组件模板内容可以是模板字符串(ES6语法)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue组件的注意事项</title>
</head>

<body>
    <div id="app">
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    Vue.component('button-count', {
        //data必须是一个函数
        data() {
            return {
                count: '0',
            }
        },
        //组件模板的内容必须是单个根元素 且可以使用模板字符串语法
        template: `
            <div>
                <button @click='count++'>点击{{count}}次</button>
                <button>按钮</button>
            </div>       
        `

    })
    let vm = new Vue({
        el: "#app",
        data: {

        }

    })
</script>

</html>

image

组件的命名方式

image.png

注意事项

  • 驼峰方式的命名能在组件注册的字符串模板中使用,但不能在标签中的模板字符串使用
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue组件的命名</title>
</head>

<body>
    <div id="app">
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
        <button-count></button-count>
        <myComponent></myComponent>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    Vue.component('myComponent', {
        data() {
            return {
                msg: 'hello Word'
            }
        },
        template: `<div>{{msg}}</div>`
    })
    Vue.component('button-count', {
        //data必须是一个函数
        data() {
            return {
                count: '0',
            }
        },
        //   采用驼峰式命名的方式可以在组件定义中的模板字符串使用
        template: `
            <div>
                <button @click='count++'>点击{{count}}次</button>
                <button>按钮</button>
             
                <myComponent></myComponent>
            </div>       
        `

    })
    let vm = new Vue({
        el: "#app",
        data: {

        }

    })
</script>

</html>

image.png

Vue之局部自定义组件

使用components属性可以局部自定义组件。

image.png



<!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>
    <div id="app">
        <hello-word></hello-word>
        <hello-vue></hello-Vue>
    </div>
</body>
<script src='../vue.js'></script>
<script>
    let helloWord = {
        data() {
            return {
                msg: 'hello Word'
            }
        },
        template: `<div>{{msg}}</div>`
    };

    let helloVue = {
        data() {
            return {
                msg: 'hello Vue'
            }
        },
        template: `<div>{{msg}}</div>`
    };

    let vm = new Vue({
        el: "#app",
        data() {
            return {

            }
        },
        // 局部自定义组件
        components: {
            'hello-word': helloWord,
            'hello-vue': helloVue
        }
    })
</script>

</html>

image.png

Vue之调试工具的使用

image.png
image.png

组件间数据交互

子组件向父组件传递数据

image.png
image.png

<!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>
    <div id="app">
        <div>{{value}}</div>
        <menu-item v-bind:title='title' v-bind:value='value'></menu-item>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 子组件向父组件传值的基本使用
    Vue.component('menu-item', {
        props: ['title', 'value'],
        data() {
            return {
                msg: "子组件本身的内容"
            }
        },
        template: `<div>{{msg +'---'+title+'---'+value}}</div>`
    })
    let vm = new Vue({
        el: "#app",
        data() {
            return {
                value: "父组件的内容",
                title: '动态绑定属性'
            }
        },
    })
</script>

</html>

image.png

props属性名规则

  • 在props中使用驼峰式命名,标签模板中需要使用短横线形式
  • 字符串的模板并没有限制

image.png

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>props的属性名规则</title>
</head>

<body>
    <div id="app">

        <div>{{msg}}</div>
        <menu-item :menu-item='title'></menu-item>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 父组件向子组件传值 props的属性名规则

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

    var vm = new Vue({
        el: "#app",
        data() {
            return {
                msg: 'hello word',
                title: 'props的命名规则'
            }
        },
    })
</script>

</html>

image.png

props属性值类型

  • 字符串String
  • 数值 Number
  • 布尔值 Boolean
  • 数组 Array
  • 对象 Object
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue之props属性值的类型</title>
</head>

<body>
    <div id="app">
        <menu-item :string='string' :number='number' :boolean='boolean' :arr='arr' :obj='obj'></menu-item>
    </div>
</body>
<script src='../vue.js'></script>
<script>
    Vue.component('menu-item', {
        props: ['number', 'string', 'boolean', 'arr', 'obj'],
        template: `<div>
            <div>{{string}}</div>
            <div>{{number}}</div>
            <div>{{boolean}}</div>
            <ul>
                <li :key='item.id' v-for='(item,index) in arr'>{{item}}</li>
            </ul>
            <div>{{obj.name}}</div>
            
            
            </div>`
    });
    let vm = new Vue({
        el: "#app",
        data() {
            return {
                string: 'hello Vue',
                number: '2',
                boolean: true,
                arr: ['apple', 'learn', 'lick'],
                obj: {
                    name: '尧子陌',
                    age: 18
                }
            }
        },
    })
</script>

</html>

image.png

子组件向父组件传值

props传递数据原则:单向数据流
子组件通过自定义事件向父组件传值

image.png

父组件监听子组件的事件

image.png

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>子组件向父组件传递值</title>
</head>

<body>
    <div id="app">
        <div :style="{fontSize:fontSize+'px'}">
            {{msg}}
        </div>
        <menu-item @large-text='handle'></menu-item>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 定义子组件
    Vue.component('menu-item', {
        template: `
        <div>
            <button @click='$emit("large-text")'> 扩大父组件的字体</button>
        </div>`
    })
    let vm = new Vue({
        el: '#app ',
        data() {
            return {
                msg: '父组件的container ',
                fontSize: 10,
            }
        },
        methods: {
            handle: function() {
                this.fontSize += 10;
            }
        },
    })
</script>

</html>

image

子组件向父组件传递值且传递参数

image.png
image.png

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>子组件向父组件传递值</title>
</head>

<body>
    <div id="app">
        <div :style="{fontSize:fontSize+'px'}">
            {{msg}}
        </div>
        <menu-item @large-text='handle($event)'></menu-item>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 定义子组件
    Vue.component('menu-item', {
        template: `
        <div>
            <button @click='$emit("large-text",5)'> 扩大父组件的字体</button>
            <button @click='$emit("large-text",20)'> 扩大父组件的字体</button>
        </div>`
    })
    let vm = new Vue({
        el: '#app ',
        data() {
            return {
                msg: '父组件的container ',
                fontSize: 10,
            }
        },
        methods: {
            handle: function(val) {
                this.fontSize += val;
            }
        },
    })
</script>

</html>

image

非父子组件间传值

image.png

image.png

<!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>
    <div id="app">
        <div>{{msg}}</div>
        <button @click='handle'></button>
        <item-tom></item-tom>
        <item-juy></item-juy>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 提供事件中心
    let hub = new Vue()
        // 创建子组件
    Vue.component('item-tom', {
        data() {
            return {
                num: 0,
            }
        },
        template: `
            <div>
                <div>{{num}}</div>
                 <button @click='handle'>按钮</button>
             </dv>
        `,
        // 触发兄弟组件的事件
        methods: {
            handle: function() {
                hub.$emit('juy-event', 2)
            }
        },

        mounted() {
            // 监听事件
            hub.$on('tom-event', (val) => {
                this.num += val;
            })
        },
    })

    // 创建子组件
    Vue.component('item-juy', {
        data() {
            return {
                num: 0,
            }
        },
        template: `
            <div>
                <div>{{num}}</div>
                 <button @click='handle'>按钮</button>
             </dv>
        `,
        methods: {
            // 触发兄弟组件的事件
            handle: function() {
                hub.$emit('tom-event', 2)
            }
        },

        mounted() {
            // 监听事件
            hub.$on('juy-event', (val) => {
                this.num += val;
            })
        },
    })
    let vm = new Vue({
        el: "#app",
        data() {
            return {
                msg: '父组件',
            }
        },
        methods: {
            handle: function() {
                hub.$off('tom-event');
                hub.$off('juy-event')
            }
        },

    })
</script>

</html>

image

组件插槽

插槽的基本用法

如果子组件没有使用插槽,父组件如果需要往子组件内容, 是没法做到的

image.png
插槽内容
image.png
插槽位置
image.png

注意事项

  • 若slot里面有默认内容,则显示默认内容,若没有文字,则显示父组件模板中的slot的内容
<!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>
    <div id="app">
        <alert-box>container</alert-box>
        <alert-box></alert-box>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    //创建子组件
    Vue.component('alert-box', {
        template: `
                <div>
                    <strong>Error</strong>
                    <slot>hello word</slot>
                </div>
        `
    })
    let vm = new Vue({
        el: '#app',
        data: {

        }
    })
</script>

</html>

image.png

具名插槽

具名卡槽的用法
image.png

<!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>
    <div id="app">
        <base-lay>
            <p slot='header'>header</p>
            <p>main</p>
            <p>main</p>
            <p slot='footer'>footer</p>

        </base-lay>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 定义子组件
    Vue.component('base-lay', {
        template: `<div>
                <header>
                    <slot name='header'></slot>
                </header>
                <main>
                    <slot></slot>
                </main>
                <footer>
                    <slot name='footer'></slot>
                </footer>
        
            </div>
            `
    })
    let vm = new Vue({
        el: '#app',
        data() {
            return {

            }
        },

    })
</script>

</html>

image.png

作用域插槽

应用场景:父组件对子组件内容进行加工处理
image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue作用域插槽</title>
    <style>
        .current {
            background-color: purple;
        }
    </style>
</head>

<body>
    <div id="app">
        <fruit-list v-bind:list='list'>
            <template slot-scope="slotProps">
               <span v-if='slotProps.info.id==3' class="current">{{slotProps.info.name}}</span>
               <span v-else>{{slotProps.info.name}}</span>
            </template>
        </fruit-list>
    </div>
</body>
<script src="../vue.js"></script>
<script>
    // 定义子组件
    Vue.component('fruit-list', {
        props: ['list'],
        template: `<div>
                <ul>
                    <li :key='item.id' v-for='(item,index) in list'>
                        <slot :info='item' >{{item.name}}</slot>
                    </li>
                  </ul>
            </div>
            `

    })
    let vm = new Vue({
        el: '#app',
        data() {
            return {
                list: [{
                    id: 1,
                    name: 'apple'
                }, {
                    id: 2,
                    name: 'orange'
                }, {
                    id: 3,
                    name: 'banner'
                }, ]
            }
        },
    })
</script>

</html>

image.png


已注销
54 声望3 粉丝

保持呼吸 坚持学习


« 上一篇
Vue常用特性
下一篇 »
Vue前后端交互