又一款MVVM组件 构建自己的Vue组件(2)

发布时间 - 2026-01-11 00:08:53    点击率:

前言:转眼距离上篇JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少。经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博主都没什么太大的关系,博主还是老老实实研究自己的技术吧。技术之路还很长,且行且研究吧。

一、为什么组件很重要

前两天,看到一篇关于汇总vue开源项目的文章,资源非常丰富,不得不感叹开源社区的强大。随便点进去看了几个UI组件,基本都不是原生的html用法,如果你不懂Vue的组件相关概念,看到一些“稀奇古怪”的标签写法,可能会使用,但肯定无法理解为什么可以这么写。比如我们随便找了一个名叫IView的来看看:

<i-input type="text" :value.sync="formInline.user" placeholder="Username">
 <Icon type="ios-person-outline" slot="prepend"></Icon>
</i-input>

这样一段代码就能得到如下效果:

博主好奇心重,打算一探究竟,今天就和大家一起来看一看这些“古怪”写法的出处。希望通过本文,让你有一种“哦,原来是这样,不过如此嘛!”的感觉!

二、Vue里面的组件基础知识

1、组件的概念

官方定义:组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

博主理解:Vue里面的组件可以理解为通过对普通html标签的封装,得到一套独立而且可以通用的html标签,我们在页面里面使用这些标签传入相应的参数即可调用封装好的组件。通过下面这张图相信可以一目了然。

由普通的html标签form、input、button、label组成了一个新的元素集合,我们命名为i-form,这个i-form就是vue里面组件的概念。我们在页面里面使用<i-form></i-form>时,通过vue的组件渲染机制,在浏览器里面最终就可以显示成为普通的html标签form、input、button、label。

2、组件原理

通过上图我们知道,vue里面的组件实际上就是一些普通html元素的集合。那么,它是如何将这些自定义标签转换为普通html标签的呢?在介绍组件原理之前,还是先来看一个最简单的组件实例。

<div style="text-align:center;margin-top:200px;" id="app">
 <!-- 3. 在Vue实例里面使用组件-->
 <b-component></b-component>
 </div>

 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">
 // 1.创建组件构造器
 var myComponent = Vue.extend({
  template: '<div id="bComponent">我是自定义组件的内容</div>'
 });

 //2.注册组件到vue里面
 Vue.component('b-component', myComponent)

 new Vue({
  el: '#app',
 });
 
 </script>

得到效果:

整个过程不难理解,主要分为三个大的步骤:

  1. 定义一个组件构造器,声明组件要渲染的html内容
  2. 将组件构造器注册到Vue的组件系统里面,使其成为Vue的一个组件,给组件取一个名称,比如b-component
  3. 在Vue的实例里面使用组件。因为上面两步定义了Vue的组件,既然是Vue的组件,那么要使用组件,首先得有一个Vue的实例,组件必须要在Vue的实例里面使用。

在网上找到一张图可以清晰地解释组件的整个渲染过程。

其实有时为了简便,我们常将1、2步合并,代码如下:

<div style="text-align:center;margin-top:200px;" id="app">
 <!-- 2. 在Vue实例里面使用组件-->
 <b-component></b-component>
 </div>

 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">
 //1.创建组件构造器,注册组件到vue里面
 Vue.component('b-component', {
  template: '<div id="bComponent">我是自定义组件的内容</div>'
 })

 new Vue({
  el: '#app',
 });
 
 </script>

得到的结果和上述相同。

3、组件使用

上述解释了下组件的定义和原理,关于组件的简单实用,我们主要介绍以下几个方面。

(1)组件的作用域

这个应该不难理解,组件分为全局组件和局部组件,也就是说,你可以在页面上面定义一个全局组件,页面上面的任何Vue实例都可使用;而对于局部组件,是和具体的Vue实例相关的,只能在当前Vue实例里面使用组件。还有一点需要说明:组件必须在Vue的实例里面使用,在Vue实例之外使用组件无效。通过下面一个例子即可清晰说明它们的区别。

<body>
 <div style="text-align:center;margin-top:50px;" id="app">
 <b-component></b-component>
 <b-component2></b-component2>
 </div>
 <div style="text-align:center;margin-top:50px;" id="app2">
 <b-component></b-component>
 <b-component2></b-component2>
 </div>

 <b-component></b-component>
 <b-component2></b-component2>
 
 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">

 //定义组件
 Vue.component('b-component', {
  template: '<div id="bComponent">我是全局组件,任何Vue实例都可使用</div>'
 })

 new Vue({
  el: '#app',
  components: {
  'b-component2': {
   template: '<div id="bComponent">我是局部组件,只能在app这个div里面使用</div>'
  }
  }
 });
 new Vue({
  el: '#app2',
 });
 
 </script>
</body>

得到结果:

(2)组件的传值

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。这段话怎么理解呢?我们先来看几个例子。

静态Prop

我们先来看看下面的一段简单的代码

<body>
 <div style="text-align:center;margin-top:50px;" id="app">
 <b-component componentmessage="你好"></b-component>
 </div>
 
 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">
 Vue.component('b-component', {
  template: '<div>{{componentmessage}}</div>',
  props: ['componentmessage'],
 })

 new Vue({
  el: '#app'
 });
 </script>
</body>

通过在组件里面使用props属性,将外部的值传入组件模板。最终渲染到页面上面就得到“<div>你好</div>”这么一段html

动态Prop

在多数情况下,我们在使用Vue实例的时候,一般通过data属性传入模型,比如

new Vue({
   el: '#app',
   data: {
    name: 'Jim',
    Age: '28'
   }
  });

这个时候,我们的name和age如何传到组件实例里面呢?

<body>
 <div style="text-align:center;margin-top:50px;" id="app">
  <b-component v-bind:my-name="name" v-bind:my-age="Age"></b-component>
 </div>
 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">
  Vue.component('b-component', {
   template: '<div>姓名:{{myName}},年龄:{{myAge}}</div>',
   props: ['myName', 'myAge'],
  })

  new Vue({
   el: '#app',
   data: {
    name: 'Jim',
    Age: '28'
   }
  });
 </script>
</body>

得到结果

需要说明几点:

在使用标签<b-component>的时候,通过v-bind命令,将Vue实例里面的name、Age属性以别名my-name、my-age的形式传入组件实例。

为什么my-name、my-age传到组件里面就变成了['myName', 'myAge']呢?这是因为在子组件中定义prop时,使用了camelCase命名法。由于HTML特性不区分大小写,camelCase的prop用于特性时,需要转为 kebab-case(短横线隔开)。

很多情况下,v-bind可以简写为冒号(:),所以上述代码也可以这么写:<b-component :my-name="name" :my-age="Age"></b-component>。效果也是一样。

这里很恶心的还有一点,在Props里面定义的必须要使用所谓“驼峰式”的方式来定义变量,否则会因为一个变量名大小写搞死你。比如props:["myName"]这样可以正确,但是如果props:["myname"]这样的话就错误,使用myname取值会是undefined。博主第一次玩这个玩意找了好半天,新手一定注意,大坑,大坑,大坑!慎入!

在封装组件里面,props属性使用非常多,更多props用法可参见文档https://vuefe.cn/v2/guide/components.html

(3)组件的插槽

在使用组件的时候,我们经常需要在组件实例向组件模板传入html元素,这个时候我们就需要在组件的模板标签里面留一些占位符(俗称“坑”),然后在具体的组件实例里面传入标签来填“坑”,在Vue里面这些“坑”也叫插槽,使用<slot>来解决。对于开发人员来说,这个其实不陌生,从原来的母版页到现在的layout页面,基本都是使用的这种原理。

<body>
 <div style="text-align:center;margin-top:50px;" id="app">
  <b-component>
   <h1 slot="header">这里可能是一个页面标题</h1>
   <h2 slot="content">姓名:{{name}},年龄:{{Age}}</h2>
   <h1 slot="footer">尾部</h1>
  </b-component>
 </div>
 <template id="slottest">
  <div class="container">
   <header>
    <slot name="header"></slot>
   </header>
   <main>
    <slot name="content"></slot>
   </main>
   <footer>
    <slot name="footer"></slot>
   </footer>
  </div>
 </template>
 
 <script src="Content/vue/dist/vue.js"></script>
 <script type="text/javascript">

  Vue.component('b-component', {
   template: '#slottest',
  })

  new Vue({
   el: '#app',
   data: {
    name: 'Jim',
    Age: '28'
   }
  });
 </script>
</body>

得到结果

上述代码应该不难理解,就是一个“挖坑”和“填坑”的过程。顺便要提一笔的是,Vue的组件支持使用<templete>的模式来定义标签模板,使用更加灵活和方便。

三、封装自己的Component

以上讲了这么多,都是关于Vue里面Component组件的一部分主要知识点,其他还有很多都没有展开说,因为这方面的文档也是相当丰富,园子里面keepfool的博文关于Vue组件的部分就介绍得非常详细,再者,Vue中文文档也是有很详细的用法说明。接下来,博主打算通过几个实例来说明使用组件给我们前端开发带来的好处。

1、使用Component封装bootstrapTable

对于项目里面的表格展示,可以基于Vue可以自己开发一套,但是说实话,这个工程量还是蛮大的,并且如果要做好,要兼容很多表格的功能,从零开始去重复造轮子实在是有点太耗时。博主项目里面大部分的表格用的bootstrapTable组件,于是博主一直在想能不能封装一套基于Vue的bootstrapTable的用法。网上也找不到类似的封装示例,大部分使用vue的框架都会自己去实现一套自己的表格样式。于是打算自己动手试试,正好也可以熟悉下component的用法。

首先新建一个js文件命名为vue.bootstrapTable.js。博主直接将代码贴出来,如果有不完善的地方,希望大家斧正。

(function ($) {
 //表格初始化的默认参数
 var defaults = {
  method: 'get',      
  toolbar: '#toolbar',    
  striped: true,      
  cache: false,      
  pagination: true,     
 };
 //注册bootstrapTable组件
 Vue.component('bootstrap-table', {
  template: '<table></table>',
  props: {
   'tableParam': { type: Object }
  },
  //组件渲染之前
  created: function () {
   //debugger;

  },
  //组件渲染之后
  mounted: function () {
   debugger;
   var params = $.extend({}, defaults, this.tableParam || {});
   this.bootstraptable = $(this.$el).bootstrapTable(params);
  }
 });

})(jQuery);

然后再界面上面

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title></title>
 <link href="Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
 <link href="Content/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
</head>
<body>
 <div id="app">
  <bootstrap-table :table-param="tableParam"></bootstrap-table>
 </div>

 <script src="Content/jquery-1.9.1.min.js"></script>
 <script src="Content/bootstrap/js/bootstrap.js"></script>
 <script src="Content/bootstrap-table/bootstrap-table.js"></script>
 <script src="Content/vue/dist/vue.js"></script>
 <script src="Content/vue-component/vue.bootstrapTable.js"></script>
 <script type="text/javascript">
  var testData = [
  { Name: 'Jim', Age: 30, Remark: '鸡母格林' },
  { Name: 'Kate', Age: 28, Remark: '凯特' },
  { Name: 'Lucy', Age: 20, Remark: '露西' },
  { Name: 'Uncle Wang', Age: 45, Remark: '严厉的王老师' }
  ];

  new Vue({
   el: '#app',
   data: {
    tableParam: {
     data: testData,
     columns: [
      {
       field: 'Name',
       title:'姓名'
      }, {
       field: 'Age',
       title: '年龄'
      }, {
       field: 'Remark',
       title: '备注'
      }]
    },
   }
  });
  
 </script>
</body>

最后测试结果:

纵观这数十行代码,基本原来其实很简单,通过组件的props功能将<bootstrap-table>实例中的初始化参数传到组件模板里面,然后再组件加载完成之后初始化bootstrapTable,最后将bootstrapTable的实例给到组件,这样在就可以通过Vue的实例通过子组件调用到当前初始化的bootstrapTable对象。

2、封装select

关于select的封装,还是打算基于第三方组件来做。同样的,我们新建一个js文件,命名为vue.bootstrapSelect.js,其代码如下:

(function ($) {
 $("body").append('<template id="bootstrapSelect">' +
  '<select class="selectpicker" v-if="myMultiple" v-bind:data-live-search="mySearch" multiple>' +
   '<option v-for="item in myDatasource" v-bind:value="item.value">{{item.text}}</option>'
  +'</select>' +
  '<select class="selectpicker" v-else v-bind:data-live-search="mySearch">' +
   '<option v-for="item in myDatasource" v-bind:value="item.value">{{item.text}}</option>'
  +'</select>' +
 '</template>');

 Vue.component('bootstrap-select', {
  template: '#bootstrapSelect',
  props: ['myDatasource', 'myMultiple', 'mySearch'],
  //组件渲染之前
  created: function () {
  },
  //组件渲染之后
  mounted: function () {   
  }
 });

})(jQuery);

页面使用

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title></title>
 <link href="Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
 <link href="Content/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
 <link href="Content/bootstrap-select/css/bootstrap-select.css" rel="stylesheet" />
</head>
<body>
 <div id="app">
  <bootstrap-select :my-datasource="selectOptions.data"
       :my-multiple="selectOptions.multiple" 
       :my-search="selectOptions.search">
  </bootstrap-select>
 </div>
 <script src="Content/jquery-1.9.1.min.js"></script>
 <script src="Content/bootstrap/js/bootstrap.js"></script>
 <script src="Content/bootstrap-table/bootstrap-table.js"></script>
 <script src="Content/bootstrap-select/js/bootstrap-select.js"></script>
 <script src="Content/bootstrap-select/js/i18n/defaults-zh_CN.js"></script>
 <script src="Content/vue/dist/vue.js"></script>
 <script src="Content/vue-component/vue.bootstrapSelect.js"></script>
 <script type="text/javascript">
  $(function () {
   var vm = new Vue({
    el: '#app',
    data: {
     selectOptions:{
      multiple: false,//多选
      search: true,//搜索
      data: [
       { text: "北京市", value: 1 },
       { text: "上海市", value: 2 },
       { text: "重庆市", value: 3 },
      ]
     }
    },
   });
  });
 </script>
</body>
</html>

得到效果:

然后可配置多选,将初始化参数multiple设置为true即可。

为什么模板里面会有两个select标签?原因就在于那个multiple,因为只要标签里面出现了multiple,select就自动多选,把multiple的值设置为任何属性都不好使,这不做了一个if判断,如果哪位有更好的方法,欢迎指出,不胜感激!

3、查看其他Vue框架源码

现在再来看文章的开头那段html

<i-input type="text" :value.sync="formInline.user" placeholder="Username">
  <Icon type="ios-person-outline" slot="prepend"></Icon>
</i-input>

结合Vue组件的文档,其实上述就是一个对input标签做的封装。

当然,以上只是component的基础,组件的封装还得结合很多其他的东西,要读懂那些框架的源码还需要学习一些其他知识,但至少通过本文希望能够让你了解这些东西的由来。

四、总结

本篇到此结束,通过本文,相信你对Vue的component有了一个大概的了解。接下来如果有时间将结合webpack介绍Vue的一些高级用法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Vue组件  # bootstrap  # table  # bootstrapSelect.js  # Vue的MVVM实现方法  # Vue原理剖析 实现双向绑定MVVM  # JS组件系列之MVVM组件 vue 30分钟搞定前端增删改查  # JS组件系列之MVVM组件构建自己的Vue组件  # 前端 Vue.js 和 MVVM 详细介绍  # 又一款MVVM组件 Vue基础语法和常用指令(1)  # Vue.js 和 MVVM 的注意事项  # JavaScript的MVVM库Vue.js入门学习笔记  # vue  # angular  # avalon这三种MVVM框架优缺点  # vue实现简单的MVVM框架  # 我是  # 自己的  # 自定义  # 几个  # 插槽  # 都是  # 命名为  # 文档  # 让你  # 多选  # 情况下  # 然后再  # 找了  # 这个时候  # 设置为  # 开源  # 就可以  # 新建一个  # 的是  # 格林 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何在宝塔面板创建新站点?  html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】  Laravel Session怎么存储_Laravel Session驱动配置详解  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  新三国志曹操传主线渭水交兵攻略  LinuxCD持续部署教程_自动发布与回滚机制  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  ,交易猫的商品怎么发布到网站上去?  WordPress 子目录安装中正确处理脚本路径的完整指南  如何在云主机上快速搭建多站点网站?  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  Laravel如何自定义错误页面(404, 500)?(代码示例)  潮流网站制作头像软件下载,适合母子的网名有哪些?  Java解压缩zip - 解压缩多个文件或文件夹实例  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  Laravel如何使用Gate和Policy进行授权?(权限控制)  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  长沙企业网站制作哪家好,长沙水业集团官方网站?  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  php结合redis实现高并发下的抢购、秒杀功能的实例  浅谈redis在项目中的应用  制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  北京专业网站制作设计师招聘,北京白云观官方网站?  Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  如何在自有机房高效搭建专业网站?  Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】  html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】  Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】  iOS验证手机号的正则表达式  网站制作大概多少钱一个,做一个平台网站大概多少钱?  如何在七牛云存储上搭建网站并设置自定义域名?  如何打造高效商业网站?建站目的决定转化率  制作企业网站建设方案,怎样建设一个公司网站?  进行网站优化必须要坚持的四大原则  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  php做exe能调用系统命令吗_执行cmd指令实现方式【详解】  如何在不使用负向后查找的情况下匹配特定条件前的换行符  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  简单实现jsp分页  什么是JavaScript解构赋值_解构赋值有哪些实用技巧