前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互

文章目录

  • Vue全家桶之组件化开发
  • 一、 组件化开发想法:
    • 1. 组件化思想体现:
    • 2. 组件化规范: web components
  • 二、注册组件:
    • 1. 组件全局注册:
    • 2. 组件使用:
    • 3. 示例:
    • 4. 局部组件注册:
  • 三、Vue调试工具:
    • 1. 工具安装步骤:
  • 四、组件间数据交互:
    • 1. 父组件向子组件传值:
    • 2. props属性值类型:
    • 3.子组件向父组件传值:
    • 4. 兄弟组件之间的传递:
      • 4.1 单独的事件中心管理组件间的通信:
      • 4.2 监听事件与销毁事件:
      • 4.3 触发事件:
      • 4.4 实例:
    • 5. 组件插槽:
      • 5.1 组件插槽的作用:
      • 5.2 插槽位置:
      • 5.3 插槽内容:
    • 6. 具名插槽:
    • 7. 作用域插槽:
  • 五、案例:购物车:
    • 1. 需求分析:
    • 2. 实现步骤:
      • 3. 代码实现:

Vue全家桶之组件化开发

一、 组件化开发想法:

1. 组件化思想体现:

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

前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互_第1张图片

2. 组件化规范: web components

希望:

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

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

二、注册组件:

1. 组件全局注册:

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

注意:

  • 全局组件注册后,任何vue实例都可以用
  • 组件参数的data值必须是函数同时这个函数要求返回一个对象;
  • 组件模板必须是单个根元素;
  • 组件模板的内容可以是模板字符串;
  • 组件的命名方式:
    • 短横线(’-’)
    • 驼峰命名: 不能在根组件中使用, 只能在模板字符串中使用;

2. 组件使用:

3. 示例:

在这里插入图片描述

<head>
    <title>注册组件title>
head>
<body>
    <div id="app">
        <button-counter>button-counter>
    div>
     
    <script src="../vue.js">script>
    <script>
        // 注册组件
        Vue.component('button-counter', {
            data: function() {
                return {
                    count: 0
                }
            },
            template: ""
        })
        var vm = new Vue({
            el: "#app",
            data: {

            }
        })
    script>
body>

4. 局部组件注册:

只能在当前注册它的vue示例中使用;

<head>
    <title>注册组件title>
head>
<body>
    <div id="app">
        <button-counter>button-counter>

        
        <hello-world>hello-world>
        <hello-tom>hello-tom>
    div>
    
    <script src="../vue.js">script>
    <script>
        // 注册组件
        Vue.component('button-counter', {
            data: function() {
                return {
                    count: 0
                }
            },
            template: ""
        });
        var HelloWorld = {
            data: function(){
                return {
                msg: 'HelloWorld'
                }
            },
            template: '
{{msg}}
'
}; var HelloTom = { data: function() { return { msg: 'HelloTom' } }, template: '
{{msg}}
'
}; var vm = new Vue({ el: "#app", data: { }, components: { // 注册局部组件 'hello-world': HelloWorld, 'hello-tom': HelloTom } });
script> body>

三、Vue调试工具:

网址: https://github.com/vuejs/vue-devtools

1. 工具安装步骤:

  • 克隆仓库;
  • 安装依赖包;
npm install
  • 构建;
  • 打开Chrome扩展页面;
  • 选中开发者模式;
  • 加载已解压的扩展, 选择shell/chrome

四、组件间数据交互:

1. 父组件向子组件传值:

  • 父组件发送的形式是以属性的形式绑定值到子组件身上;
  • 然后子组件用属性props接收;
  • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制;
Vue.component('menu-item', {
	props: ['title'],
	template: `
		
{{title}}
` })
  • 父组件通过属性将值传递给子组件


<div id="app">
  <div>{{pmsg}}div>
   
   
  <menu-item title='来自父组件的值'>menu-item>
  
  <menu-item :title='ptitle' content='hello'>menu-item>
div>

<script type="text/javascript">
  Vue.component('menu-item', {
    // 3、 子组件用属性props接收父组件传递过来的数据  
    props: ['title', 'content'],
    data: function() {
      return {
        msg: '子组件本身的数据'
      }
    },
    template: '
{{msg + "----" + title + "-----" + content}}
'
}); var vm = new Vue({ el: '#app', data: { pmsg: '父组件中内容', ptitle: '动态绑定属性' } });
script>

2. props属性值类型:

  • 字符串: String;
  • 数值: number;
  • 布尔值: boolean
  • 数组: array
  • 对象: object;

3.子组件向父组件传值:

  • 子组件通过自定义事件向父组件传递信息:

$emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据;

  • 父组件用v-on 监听子组件的事件;

 <div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}div>
     	
    <menu-item :parr='parr' @enlarge-text='handle($event)'>menu-item>
  div>
  <script type="text/javascript" src="js/vue.js">script>
  <script type="text/javascript">
    /*
      子组件向父组件传值-携带参数
    */
    
    Vue.component('menu-item', {
      props: ['parr'],
      template: `
        
  • {{item}}
### 1、子组件用$emit()触发事件 ### 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
`
}); var vm = new Vue({ el: '#app', data: { pmsg: '父组件中内容', parr: ['apple','orange','banana'], fontSize: 10 }, methods: { handle: function(val){ // 扩大字体大小 this.fontSize += val; } } });
script>

4. 兄弟组件之间的传递:

4.1 单独的事件中心管理组件间的通信:

前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互_第2张图片

var eventHub = new Vue()

4.2 监听事件与销毁事件:

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

eventHub.$off('add-todo')

4.3 触发事件:

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

4.4 实例:

前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互_第3张图片

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>兄弟组件传值title>
head>
<body>
    <div id="app">
        <test-tom>test-tom>
        <test-jerry>test-jerry>
    div>
    <script src="../vue.js">script>
    <script>
        /* 兄弟组件间传值 */

        // 事件中心
        var hub = new Vue();

        Vue.component('test-tom', {
            data: function() {
                return {
                    num: 0
                }
            },
            template: `
                
Tom: {{num}}
`
, methods: { handle: function() { // 触发兄弟组件的事件 hub.$emit('jerry-event', 1); } }, mounted: function() { // 监听事件 hub.$on('tom-event', (val) => { this.num += val; }) } }); Vue.component('test-jerry', { data: function() { return { num: 0 } }, template: `
Jerry: {{num}}
`
, methods: { handle: function() { // 触发兄弟组件的事件 hub.$emit('tom-event', 2); } }, mounted: function() { // 监听事件 hub.$on('jerry-event', (val) => { this.num += val; }) } }) var vm = new Vue({ el: "#app", data: { } })
script> body>

5. 组件插槽:

5.1 组件插槽的作用:

父组件系那个子组件传递模板内容
前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互_第4张图片

5.2 插槽位置:

Vue.component('alert-box', {
	template: `
		
Error!
`
})

5.3 插槽内容:

<alert-box>someting bad requestd!alert-box>

6. 具名插槽:

  • 具有名字的插槽
  • 使用 中的 “name” 属性绑定元素
<head>
    <title>具名插槽title>
head>
<body>
    <div id="app">
        <base-layout>
            
          <p slot='header'>标题信息p>
          <p>主要内容1p>
          <p>主要内容2p>
          <p slot='footer'>底部信息信息p>
        base-layout>
    
        <base-layout>
            
          <template slot='header'>
            <p>标题信息1p>
            <p>标题信息2p>
          template>
          <p>主要内容1p>
          <p>主要内容2p>
          <template slot='footer'>
            <p>底部信息信息1p>
            <p>底部信息信息2p>
          template>
        base-layout>
      div>
      <script type="text/javascript" src="../vue.js">script>
      <script type="text/javascript">
        /*
          具名插槽
        */
        Vue.component('base-layout', {
          template: `
            
### 1、 使用 中的 "name" 属性绑定元素 指定当前插槽的名字
### 注意点: ### 具名插槽的渲染顺序,完全取决于模板,而不是取决于父组件中元素的顺序
`
}); var vm = new Vue({ el: '#app', data: { } });
script> body>

7. 作用域插槽:

  • 父组件对子组件加工处理;
  • 既可以复用子组件的slot,又可以使slot内容不一致;

在这里插入图片描述

<head>
    <title>作用域插槽title>
    <style>
        .current {
            color: orange;
        }
    style>
head>
<body>
    <div id="app">
        <fruit-list :list='list'>
            <template slot-scope='slotProps'>
                <strong :class="slotProps.info.id == 2?'current': ''">{{slotProps.info.name}}strong>
            template>
        fruit-list>
    div>
    <script src="../vue.js">script>
    <script>
        /* 作用域插槽 */
        Vue.component('fruit-list', {
            props: ['list'],
            template: `
                
  • {{item.name}}
  • `
    }); var vm = new Vue({ el: "#app", data: { list: [ { id:1, name: 'apple' }, { id: 2, name: 'orange' }, { id: 3, name: 'banana' } ] } })
    script> body>

    五、案例:购物车:

    前端学习之VUE基础三:组件化开发想法、注册组件、组件间数据交互_第5张图片

    1. 需求分析:

    按照组件化方式实现业务需求:

    • 根据业务功能进行组件化划分:
      • 标题组件: 展示文本;
      • 列表组件: 列表展示, 商品数量变更, 商品删除;
      • 结算组件: 计算商品总额;

    2. 实现步骤:

    功能实现步骤:

    • 实现整体布局和样式效果;
    • 划分独立的功能组件;
    • 组合所有的子组件形成整体结构;
    • 逐个实现各个组件功能:
      • 标题组件;
      • 列表组件;
      • 结算组件;

    3. 代码实现:

    • 没有做小于等于0的兼容!!
    <head>
        <title>购物车title>
        <style>
            .container .cart{
                width: 300px;
                margin: auto;
            }
            .container .title {
                background-color: lightblue;
                height: 40px;
                line-height: 40px;
                text-align: center;
            }
            .container .total {
                background-color: #FFCE46;
                height: 50px;
                line-height: 50px;
                text-align: right;
            }
            .container .total button {
                margin: 0 10px;
                background-color: #DC4C40;
                height: 35px;
                width: 80px;
                border: 0;
                color: #fff;
            }
            .container .total span {
                color: red;
                font-weight: bold;
            }
            .container .item {
                height: 55px;
                line-height: 55px;
                position: relative;
                border-top: 1px solid #ADD8E6;
            }
            .container .item img {
                width: 45px;
                height: 45px;
                margin: 5px;
            }
            .container .item .name {
                position: absolute;
                width: 90px;
                top: 0;
                left: 55px;
                font-size: 16px;
            }
            .container .item .change {
                width: 100px;
                position: absolute;
                top: 0;
                right: 50px;
            }
            .container .item .change a {
                font-size: 20px;
                width: 30px;
                text-decoration:none;
                background-color: lightgray;
                vertical-align: middle;
            }
            .container .item .change .num {
                width: 40px;
                height: 25px;
            }
            .container .item .del {
                position: absolute;
                top: 0;
                right: 0px;
                width: 40px;
                text-align: center;
                font-size: 40px;
                cursor: pointer;
                color: red;
            }
            .container .item .del:hover {
                background-color: orange;
            }
        style>
    head>
    <body>
        <div id="app">
            <div class="container">
               <my-cart>my-cart>
            div>
        div>
        <script src="../../vue.js">script>
        <script>
            var cartTitle = {
                props: ['uname'],
                template: `
                
    {{uname}}的商品
    `
    }; var cartList = { props: ['list'], template: `
    {{item.name}}
    {{item.price}}元
    ×
    `
    , methods: { sub:function(id) { this.$emit('change-num', { id:id, type: "sub" }) }, add: function(id) { this.$emit('change-num', { id:id, type: "add" }) }, changeNum: function(id, event) { this.$emit('change-num', { id: id, num: event.target.value, type: "change" }); }, del: function(id) { // 把id传递给父组件 this.$emit('cart-del', id); } } }; var cartTotal = { props: ['list'], template: `
    总价:{{total}}
    `
    , computed: { total: function() { // 计算商品总价 var t = 0; this.list.forEach(item => { t += (item.price * item.num); }) return t; } } }; Vue.component('my-cart', { data: function() { return { uname: '张三', list: [ { id: 1, name: "TCL电视", price: 1000, num: 1, img: 'images/a.jpg' }, { id: 2, name: "机顶盒", price: 1000, num: 2, img: 'images/b.jpg' }, { id: 3, name: "海尔冰箱", price: 1000, num: 3, img: 'images/c.jpg' }, { id: 4, name: "小米手机", price: 1000, num: 4, img: 'images/d.jpg' }, { id: 5, name: "pptv", price: 1000, num: 5, img: 'images/e.jpg' } ] } }, template: `
    `
    , components: { 'cart-title': cartTitle, 'cart-list': cartList, 'cart-total': cartTotal }, methods: { changeNum: function(val) { this.list.some(item => { if (val.type == "add") { if(item.id == val.id) { item.num += 1; } } else if(val.type == "sub"){ if(item.id == val.id) { item.num -=1; } } else { if(item.id == val.id) { item.num = val.num; } } }) }, delCart:function(id){ // 根据id删除list中对应的数据 // 1. 找到id对应的数据 var index = this.list.findIndex(item => { return item.id == id; }); // 2. 根据索引删除数据 this.list.splice(index, 1); }, } }) var vm = new Vue({ el: "#app", data: { } });
    script> body>

    你可能感兴趣的:(前端学习,#,Vue)