Vue全家桶之组件化开发

Posted 前端加油

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue全家桶之组件化开发相关的知识,希望对你有一定的参考价值。

Vue全家桶之组件化开发

1. 组件化开发思想

组件是可复用的 Vue 实例, 把一些公共的模块抽取出来,然后写成单独的的工具组件或者页面,在需要的页面中就直接引入即可,那么我们可以将其抽出为一个组件进行复用,提高了代码的复用率

组件化开发思想:如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。

在这里插入图片描述
在这里插入图片描述

  • 我们将一个完整的页面分成很多个组件。
  • 每个组件都用于实现页面的一个功能块。
  • 而每一个组件又可以进行细分。

组件化思想的应用

  • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
  • 尽可能的将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

2. 组件的注册

2.1 全局组件注册语法

​ 使用Vue.component('button-counter', cpnc)方式注册,直接使用<button-counter></button-counter>调用。button-counter是全局组件的名字,cpnc是定义的组件对象。

     Vue.component("button-counter", {
        data: 组件数据,
        template: 组件模块内容
      });
//注册一个名为button-counter 的新组件
Vue.component("button-counter", {
        data: function () {
          return {
            count: 0,
          };
        },
        template: '<button @click="count++">点击{{count}}次</button>',
      });

2.2 组件用法

    <div id="app">
      <!-- 组件的使用 -->
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
//1-组件的基本使用.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title></title>
  </head>
  <body>
    <div id="app">
      <!-- 全局组件的使用 -->
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
      //全局组件的注册
      Vue.component("button-counter", {
        data: function () {
          return {
            count: 0,
          };
        },
       template: `
        <div>
          <button @click="handle">点击了{{count}}次</button>
        </div>
      `,
      });
      const app = new Vue({
        el: "#app",
        data: {},
        methods: {},
      });
    </script>
  </body>
</html>

在这里插入图片描述

2.3 组件注册注意事项

  1. data必须是一个函数

    保证每个模板的数据是相互独立的

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

    只能有一个父元素,如上面代码中的div

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

    ES6 引入新的声明字符串的方式 ``

  4. 组件命名方式

    短横线方式 my-component (推荐)

    驼峰方式 MyComponent

2.4 局部组件注册

局部组件,只能在当前vue实例挂载的对象中使用,类似于局部变量,有块级作用域。

   //注册方式
   const app = new Vue({
      el:"#app",
      components:{//局部组件创建
        'hello-world': HelloWorld
      }
    })

​ 使用方式与全局变量一样,直接使用<hello-world></hello-world>调用。 'hello-world’组件命名的名字,HelloWorld定义的组件对象。

//04-局部组件用法.html
<!DOCTYPE html>
<html lang="en">

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

<body>
  <div id="app">
    <hello-world></hello-world>
  </div>
  <script type='text/javascript' src='js/vue.js'></script>
  <script type='text/javascript'>
    var HelloWorld = {
      data: function () {
        return {
          msg: 'helloworld'
        }
      },
      template: `
  <div>{{msg}}</div>
  `
    }
    const app = new Vue({
      el: "#app",
      data: {},
      components: {
        'hello-world': HelloWorld
      }
    })
  </script>
</body>

</html>

3. 组件间数据交互

3.1 父组件向子组件传值props

在这里插入图片描述

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

props传递数据原则:单向数据流,只能父传子

v-bind是不支持使用驼峰标识的,例如cUser要改成c-User

Vue.component(‘menu-item',{
    //props接受父组件传递的数据
	props: ['title'],
	template: '<div>{{ title }}</div>'
})

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

//传统方式
<menu-item title="来自父组件的数据"></menu-item>
//动态绑定
<menu-item :title="title"></menu-item>
 //07-父组件向子组件传值-props命名规则.html
<!DOCTYPE html>
 <html lang="en">

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

 <body>
   <div id="app">
     <div>{{pmsg}}</div>
	//传统方式
     <menu-item title='来自父组件的值'></menu-item>
	//动态绑定
     <menu-item :title='ptitle' content='hello'></menu-item>
   </div>
   <script type='text/javascript' src='js/vue.js'></script>
   <script type='text/javascript'>
     //相对于Vue实例为子组件 
     Vue.component('menu-item', {
       //props接受父组件传递的数据
       props: ['title', 'content'],
       data: function () {
         return {
           msg: '子组件本身的数据'
         }
       },
       template: `
     <div>{{msg + '-----' +title + '-----' +content}}</div>
     `
     })
     //Vue实例为根组件
     const app = new Vue({
       el: "#app",
       data: {
         pmsg: "父组件中内容",
         ptitle: '动态绑定的值'
       }
     })
   </script>
 </body>

 </html>

在这里插入图片描述

3.props属性名规则

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

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

    Vue.component(‘menu-item', {
    	// 在JavaScript中是驼峰式的
    	props: ['menuTitle'],
    	template: '<div>{{ menuTitle }}</div>'
    })
    //在html中是短横线方式的
    <menu-item menu-title=“nihao"></menu-item>
    

4.props属性值类型

  • 字符串String

  • 数值Number

  • 布尔值Boolean

  • 数组Array

  • 对象Object

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    <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>{{pstr}}</div>
              <div>{{12 + pnum}}</div>
              <div>{{typeof pboo}}</div>
              <ul>
                <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
              </ul>
                <span>{{pobj.name}}</span>
                <span>{{pobj.age}}</span>
              </div>
            </div>
          `
        });
        var vm = new Vue({
          el: '#app',
          data: {
            pmsg: '父组件中内容',
            pstr: 'hello',
            parr: ['apple','orange','banana'],
            pobj: {
              name: 'lisi',
              age: 12
            }
          }
        });
      </script>
    </body>
    </html>
    

在这里插入图片描述

3.2 子组件向父组件传值$emit

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

子组件向父组件传值,使用自定义事件$emit$emit(自定义事件名称)

<button @click='$emit("enlarge-text")'>扩大父组件字体</button>

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

<menu-item @enlarge-text='handle'></menu-item>
//09-子组件向父组件传值.html
<!DOCTYPE html>
<html lang="en">

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

<body>
  <!-- 整个app为父组件 -->
  <div id="app">
    <div :style='{fontSize:fontsize+"px"}'>{{msg}}</div>
    <!-- 在父组件中监听子组件事件 -->
    <menu-item @enlarge-text='handle'></menu-item>
  </div>
  <script type='text/javascript' src='js/vue.js'></script>
  <script type='text/javascript'>
    //子组件点击按钮控制父组件字体大小
    //创建子组件
    Vue.component('menu-item', {
      template: `
<button @click='$emit("enlarge-text")'>扩大父组件字体</button>
`
    })
    const app = new Vue({
      el: "#app",
      data: {
        msg: '父组件中的内容',
        fontsize: 10
      },
      methods: {
        handle: function () {
          this.fontsize += 5;
        }
      }
    })
  </script>
</body>

</html>

在这里插入图片描述

3.子组件通过自定义事件向父组件传递信息,携带额外的值

5为另外额外的值

<button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>

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

通过$event接受额外的值

<menu-item  @enlarge-text='handle($event)'></menu-item>
<!DOCTYPE html>
<html lang="en">

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

<body>
  <div id="app">
    <div :style='{fontSize:fontsize+"px"}'>{{msg}}</div>
    <menu-item @enlarge-text='handle($event)'></menu-item>
  </div>
  <script type='text/javascript' src='js/vue.js'></script>
  <script type='text/javascript'>
    Vue.component('menu-item', {
      template: `
<button @click='$emit("enlarge-text",5)'>扩大父组件字体</button>
`
    })
    const app = new Vue({
      el: "#app",
      data: {
        msg: '父组件中的内容',
        fontsize: 10
      },
      methods: {
        handle: function (val) {
          this.fontsize += val;
        }
      }
    })
  </script>
</body>

</html>

3.3 非父子组件间传值

在这里插入图片描述

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

var eventHub = new Vue()

2.监听事件与销毁事件

$on用于监听事件,add-todo为事件名称,addTodo为事件函数

$off用于销毁事件

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

3.触发事件

$emit用于触发事件,add-todo为事件名称, id为携带参数

eventHub.$emit(‘add-todo', id)
//11-兄弟组件之间数据交互.html
<!DOCTYPE html>
<html lang="en">

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

<body>
  <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type='text/javascript' src='js/vue.js'></script>
  <script type='text/javascript'>
    //提供事件中心
    var hub = new Vue()
    Vue.component('test-tom', {
      data: function () {
        return {
          num: 0
        }
      },
      template: `
    <div>
      <div>Tom:{{num}}</div>
      <div>
        <button @click='handle'>点击</button>
      </div>
    </div>
    `,
      methods: {
        handle: function () {
          //触发兄弟组件的事件
          hub.$emit('jerry-event', 2)
        }
      },
      mounted: function () {
        //监听事件
        hub.$on('tom-event', val => {
          this.num += val;
        })
      }
    })
    Vue.component('test-jerry', {
      data: function () {
        return {
          num: 0
        }
      },
      template: `
    <div>
      <div>Jerry:{{num}}</div>
      <div>
        <button @click='handle'>点击</button>
      </div>
    </div>
    `,
      methods: {
        handle: function () {
          //触发兄弟组件的事件
          hub.$emit('tom-event', 1)
        }
      },
      mounted: function () {
        //监听事件
        hub.$on('jerry-event', val => {
          this.num += val;
        })
      }
    })
    const app = new Vue({
      el: "#app",
      data: {},
      methods: {
        handle: function () {
          //销毁事件
          hub.$off('tom-event');
          hub.$off('jerry-event')
        }
      }
    })
  </script>
</body>

</html>

在这里插入图片描述

4. 组件插槽

4.1 组件插槽的作用

编译作用域:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

插槽的目的是让我们原来的设备具备更多的扩展性。比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。

组件的插槽是为了让我们封装的组件更加具有扩展性,让使用者可以决定组件内部的一些内容到底展示什么。

组件插槽的作用:父组件向子组件传递内容

在这里插入图片描述

4.2 组件插槽基本用法

在子组件中,使用特殊的元素<slot>就可以为子组件开启一个插槽。

该插槽插入什么内容取决于父组件如何使用。

如何封装合适呢?

抽取共性,保留不同。最好的封装方式就是将共性抽取到组件中,将不同预留为插槽。

1.插槽位置

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

2.插槽内容

<alert-box>Something had happened.</alert-box>
//12-插槽基本用法.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <alert-box>有bug发生</alert-box>
    <alert-box>有一个警告</alert-box>
    <alert-box></alert-box>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">

    Vue.component('alert-box', {
      template: `
        <div>
          <strong>ERROR:</strong>
          <slot>默认内容</slot>
        </div>
      `
    });
    var vm =

以上是关于Vue全家桶之组件化开发的主要内容,如果未能解决你的问题,请参考以下文章

Vue全家桶之组件化开发

Vue全家桶之组件化开发

Vue全家桶之VueX

Vue全家桶之Vue基础指令

Vue全家桶之webpack详解

Vue全家桶之Vue-router路由