vue 扩展现有组件的操作


Posted in Javascript onAugust 14, 2020

1. 使用vue.mixin全局混入

混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。mixins 选项接受一个混合对象的数组。

混入的主要用途

1、在你已经写好了构造器后,需要增加方法或者临时的活动时使用的方法,这时用混入会减少源代码的污染。

2、很多地方都会用到的公用方法,用混入的方法可以减少代码量,实现代码重用。

<h1>Mixins</h1>
  <hr>
  <div id="app">
    <p>num:{{ num }}</p>
    <P>
      <button @click="add">增加数量<tton>
    </P>
  </div>
  <script type="text/javascript">
    var addLog = { //额外临时加入时,用于显示日志
      updated: function () {
        console.log("数据发生变化,变化成" + this.num + ".");
      }
    }
    Vue.mixin({// 全局注册一个混入,影响注册之后所有创建的每个 Vue 实例
      updated: function () {
        console.log("我是全局的混入")
      }
    })
    var app = new Vue({
      el: '#app',
      data: {
        num: 1
      },
      methods: {
        add: function () {
          this.num++;
        }
      },
      updated() {
        console.log("我是原生的update")
      },
      mixins: [addLog]//混入
    })

输出的结果

vue 扩展现有组件的操作

mixins的调用顺序

从执行的先后顺序来说,混入对象的钩子将在组件自身钩子之前调用,如果遇到全局混入(Vue.mixin),全局混入的执行顺序要前于混入和组件里的方法。

2.使用extends 扩展

extends选项允许声明扩展另一个组件,而无需使用 Vue.extend。

通过外部增加对象的形式,对构造器进行扩展。它和混入mixins非常的类似。只不过接收的参数是简单的选项对象或构造函数,所以extends只能单次扩展一个组件。

var bbb = {
      updated() {
        console.log("我是被扩展出来的");
      },
      methods: {
        add: function () { //跟原生的方法冲突,取原生的方法,这点跟混入一样
          console.log('我是被扩展出来的add方法!');
          this.num++;
        }
      }
    };
    var app = new Vue({
      el: '#app',
      data: {
        num: 1
      },
      methods: {
        add: function () {
          console.log('我是原生add方法');
          this.num++;
        }
      },
      updated() {
        console.log("我是扩展出来的");
      },
      extends: bbb// 接收对象和函数
    })

vue 扩展现有组件的操作

结果

执行的先后顺序和mixins一样,另外扩展的方法与原生的冲突时,扩展的方法不生效,这点跟混入一样

ps extends和mixins优先级比较

vue 扩展现有组件的操作

相对于mixins,extends触发的优先级更高

3.加slot扩展

.默认插槽和匿名插槽

slot用来获取组件中的原内容,此方式用于父组件向子组件传递“标签数据”。有的时候为插槽提供默认的内容是很有用的,例如,一个 组件可能希望这个按钮的默认内容是“如果没有原内容,则显示该内容”,但是同时允许用户覆写为别的内容。

<body>
 <div id="itany">
  <my-hello>180812</my-hello>
 </div>
<template id="hello">
 <div>
  <h3>welcome to xiamen</h3>
  <slot>如果没有原内容,则显示该内容</slot>// 默认插槽
 </div>
</template>
<script>
 var vm=new Vue({
   el:'#itany',
   components:{
   'my-hello':{
   template:'#hello'
  }
   }
 });  
</script>

具名插槽

有些时候我们需要多个插槽, 元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽:

<div id="itany">
  <my-hello>
   <ul slot="s1">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
   </ul>
   <ol slot="s2">
  <li>111</li>
  <li>222</li>
  <li>333</li>
   </ol>
  </my-hello>
</div>
<template id="hello">
  <div>
   <slot name="s2"></slot>
   <h3>welcome to xiamen</h3>
   <slot name="s1"></slot>
  </div>
</template>
<script>
 var vm=new Vue({
  el:'#itany',
  components:{
   'my-hello':{
     template:'#hello'
    }
  }
 });

补充知识:Vue extends拓展任意组件功能(el-select实例)-两种写法

用到ElementUI的select组件,要求能够多选并且重复选择。如果直接使用的话,首先el-tag会报错,因为循环中key值重复;其次,他的移除是通过indexof搜索移除的tag的值,且在remove-tag事件中未抛出被移除tag的索引,这样的后果是存在多个相同值的tag时,只会移除第一个相同值的tag

思路

在el-tag的循环中,给close事件增加一个参数index,然后重写deleteTag方法,直接通过index删除该tag

Vue: @close="deleteTag($event, item)"
JSX: on-close={e => this.deleteTag(e, this.selected[0])}
deleteTag(event, tag, tagIndex){
 const value = this.value.slice();
 value.splice(tagIndex, 1);// 核心代码,其他代码省略
}

写法一、Vue template(推荐)

非常简单,改动特别少,可以使用Vue的所有用法,只需要复制el-select的template

新建一个vue文件

复制el-select的template模板内容过来

导入el-select,继承

覆盖methods中的deleteTag

结果

<template>
 <div
  class="el-select"
  :class="[selectSize ? 'el-select--' + selectSize : '']"
  @click.stop="toggleMenu"
  v-clickoutside="handleClose">
  我是示例代码,此处为自定义模板内容
 </div>
</template>

<script>
 import { Select} from 'element-ui';
 export default {
  extends: Select,//继承
  name: 'my-el-select',
  methods: {
   deleteTag(event, tag, tagIndex) {
// 重写该方法
  },
 },
 };
</script>

写法二、JSX(比较麻烦)

需要手动将Vue template转为jsx写法,无法使用事件修饰符,部分指令等等,改动比较大

1、导入继承

import {Select} from 'element-ui';

const myElSelect = {
 extends: Select
}

2、 重写render

Vue template最终编译之后也是生成render函数,这里覆盖render函数,

生成自定义内容。此处的意义只是为了记录以便于方便我用render函数时的jsx写法

render()
{
  const tagContent = () => {
   if (this.collapseTags && this.selected.length) {
    const tag0 = (
     <el-tag
      closable={!this.selectDisabled}
      size={this.collapseTagSize}
      hit={this.selected[0].hitState}
      type='info'
      on-close={e => this.deleteTag(e, this.selected[0])}
      disable-transitions={true}>
      <span class='el-select__tags-text'>{this.selected[0].currentLabel}</span>
     </el-tag>
    );
    const tag1 = (
     <el-tag
      closable={false}
      size={this.collapseTagSize}
      type='info'
      disable-transitions={true}>
      <span class='el-select__tags-text'>+ {this.selected.length - 1}</span>
     </el-tag>
    );

    if (this.selected.length > 1) {
     return (
      <span>
       {tag0}
       {tag1}
      </span>
     );
    }
    return (
     <span>
      {tag0}
     </span>
    );
   }
  };
  const emptyText = () => {
   if (this.emptyText && (!this.allowCreate || this.loading || (this.allowCreate && this.options.length === 0))) {
    return (
     <p class='el-select-dropdown__empty'>{this.emptyText}</p>
    );
   }
  };
  const selectOption = () => {
   return (
    <transition
     name='el-zoom-in-top'
     on-before-enter={this.handleMenuEnter}
     on-after-leave={this.doDestroy}>
     <el-select-menu
      ref='popper'
      append-to-body={this.popperAppendToBody}
      v-show={this.visible && this.emptyText !== false}>
      <el-scrollbar
       tag='ul'
       wrap-class='el-select-dropdown__wrap'
       view-class='el-select-dropdown__list'
       ref='scrollbar'
       class={{'is-empty': !this.allowCreate && this.query && this.filteredOptionsCount === 0}}
       v-show={this.options.length > 0 && !this.loading}>
       {this.showNewOption ? (
        <el-option
         value={this.query}
         created={true}>
        </el-option>
       ) : null}
       {
        this.$slots.default
       }
      </el-scrollbar>
      {emptyText()}
     </el-select-menu>
    </transition>
   );
  };
  return (
   <div
    class={['el-select', this.selectSize ? 'el-select--' + this.selectSize : '']}
    on-click={this.toggleMenu} v-clickoutside={this.handleClose}>
    <div
     class='el-select__tags'
     ref='tags'
     style={{'max-width': this.inputWidth - 32 + 'px'}}>
     {tagContent()}
     <transition-group onAfterLeave={this.resetInputHeight}>
      {this.selected.map((item, index) => {
       return (
        <el-tag
         key={index}
         closable={!this.selectDisabled}
         size={this.collapseTagSize}
         hit={item.hitState}
         type='info'
         on-close={(e) => this.deleteTag(e, item, index)}
         disable-transitions={false}>
         <span class='el-select__tags-text'>{item.currentLabel}</span>
        </el-tag>
       );
      })}
     </transition-group>
    </div>
    <el-input
     ref='reference'
     value={this.selectedLabel}
     type='text'
     placeholder={this.currentPlaceholder}
     name={this.name}
     id={this.id}
     auto-complete={this.autoComplete}
     size={this.selectSize}
     disabled={this.selectDisabled}
     readonly={this.readonly}
     validate-event={false}
     class={{'is-focus': this.visible}}
     on-focus={this.handleFocus}
     on-blur={this.handleBlur}
     on-keyup_native={this.debouncedOnInputChange}
     on-paste_native={this.debouncedOnInputChange}
     on-mouseenter_native={(this.inputHovering = true)}
     on-mouseleave_native={(this.inputHovering = false)}
    >
     <i slot='suffix'
       class={['el-select__caret', 'el-input__icon', 'el-icon-' + this.iconClass]}
       on-click={() => this.handleIconClick}/>
    </el-input>
    {selectOption()}
   </div>
  );
 }

3、 重写method里的deleteTag方法

4、结果

import {Select} from 'element-ui';

const myElSelect = {
 extends: Select,
 methods: {
  deleteTag(event, tag, tagIndex) {
   // *****略
  },
 },
 render() {
  return (
   <div>例子</div>
  );
 }
};
export default myElSelect;

以上这篇vue 扩展现有组件的操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery读取XML文件数据并显示的实现代码
Dec 16 Javascript
JQuery UI的拖拽功能实现方法小结
Mar 14 Javascript
jQuery之按钮组件的深入解析
Jun 19 Javascript
js style动态设置table高度
Oct 21 Javascript
jQuery EasyUI Dialog拖不下来如何解决
Sep 28 Javascript
用jQuery的AJax实现异步访问、异步加载
Nov 02 Javascript
JS简单实现点击按钮或文字显示遮罩层的方法
Apr 27 Javascript
jQuery选择器之子元素过滤选择器
Sep 28 jQuery
Vue利用canvas实现移动端手写板的方法
May 03 Javascript
使用svg实现动态时钟效果
Jul 17 Javascript
vue实现评价星星功能
Jun 30 Javascript
小程序实现筛子抽奖
May 26 Javascript
如何HttpServletRequest文件对象并储存
Aug 14 #Javascript
解决element-ui里的下拉多选框 el-select 时,默认值不可删除问题
Aug 14 #Javascript
Vue + Element-ui的下拉框el-select获取额外参数详解
Aug 14 #Javascript
vue在App.vue文件中监听路由变化刷新页面操作
Aug 14 #Javascript
解决vue项目中某一页面不想引用公共组件app.vue的问题
Aug 14 #Javascript
在vue中封装方法以及多处引用该方法详解
Aug 14 #Javascript
JS+css3实现幻灯片轮播图
Aug 14 #Javascript
You might like
建立文件交换功能的脚本(三)
2006/10/09 PHP
php中动态调用函数的方法
2015/03/16 PHP
PHP date函数常用时间处理方法
2015/05/11 PHP
ThinkPHP V2.2说明文档没有说明的那些事实例小结
2015/07/01 PHP
PHP使用Session实现上传进度功能详解
2019/08/06 PHP
Js 冒泡事件阻止实现代码
2013/01/27 Javascript
对Jquery中的ajax再封装,简化操作示例
2014/02/12 Javascript
JavaScript事件委托的技术原理探讨示例
2014/04/17 Javascript
jQuery实现跟随鼠标运动图层效果的方法
2015/02/02 Javascript
javascript获取元素离文档各边距离的方法
2015/02/13 Javascript
JS实现鼠标滑过链接改变网页背景颜色的方法
2015/10/20 Javascript
jQuery动态加载css文件实现方法
2016/06/15 Javascript
Bootstrap select多选下拉框实现代码
2016/12/23 Javascript
详解JavaScript中js对象与JSON格式字符串的相互转换
2017/02/14 Javascript
js调用刷新界面的几种方式
2017/05/03 Javascript
jQuery轮播图实例详解
2018/08/15 jQuery
vue2中使用sass并配置全局的sass样式变量的方法
2018/09/04 Javascript
webpack打包nodejs项目的方法
2018/09/26 NodeJs
如何能分清npm cnpm npx nvm
2019/01/17 Javascript
从零搭一个自用的前端脚手架的方法步骤
2019/09/23 Javascript
JS原型对象操作实例分析
2020/06/06 Javascript
vue监听dom大小改变案例
2020/07/29 Javascript
Javascript实现关闭广告效果
2021/01/29 Javascript
[01:34]DAC2018主赛事第四日五佳镜头 Gh巨牙海民助Miracle-死里逃生
2018/04/07 DOTA
详解python3中zipfile模块用法
2018/06/18 Python
python正则表达式之对号入座篇
2018/07/24 Python
Pytorch之Variable的用法
2019/12/31 Python
Python 格式化打印json数据方法(展开状态)
2020/02/27 Python
python读取hdfs并返回dataframe教程
2020/06/05 Python
keras 获取某层的输入/输出 tensor 尺寸操作
2020/06/10 Python
Pytorch 解决自定义子Module .cuda() tensor失败的问题
2020/06/23 Python
彪马土耳其官网:PUMA土耳其
2019/07/14 全球购物
大学计划书范文800字
2014/08/14 职场文书
学生个人评语大全
2015/01/04 职场文书
幼儿园教师个人工作总结2015
2015/05/12 职场文书
Python Flask搭建yolov3目标检测系统详解流程
2021/11/07 Python