Vue3组件(五)封装一个更好用的url组件

官网有一个url组件的例子,但是比较简陋,基本不太好用,那么我们来完善一下。

定义共用函数(改进版)

接收父组件的v-model的属性值,并且提交数据的代码抽象出来放在独立的js文件里面,这样各种组件就都可以拿来用了。

// controlManage.js
import { ref, watch } from 'vue'

/**
* 控件的赋值、提交的统一管理函数
** 属性:
* ** props: 组件的属性,获取modelValue,和meta
* ** context: 上下文获取emit,提交数据
** 返回:
* ** value:绑定到组件的值
* ** mySubmit:向父组件提交的事件
*/
const controlManage = (props, context) => {
  // 用于绑定控件的值。
  const value = ref(props.meta.defaultValue)

  // 获取父组件设置的属性
  const _value = props.modelValue

  // 设置控件值。如果有属性值(修改状态)则把属性值设置给控件值。
  if (!(_value === '' || _value === 0 || _value === null)) {
    value.value = _value
  }

  // 监听 modelValue 属性,给 value 赋值
  watch(() => props.modelValue, (v1, v2) => {
    // console.log('controlManage监听属性变化', v1)
    value.value = v1
  })

  // 向父组件提交事件
  const mySubmit = (val) => {
    context.emit('update:modelValue', val)
    context.emit('input', val)
  }

  return {
    /**
    * 用于绑定控件的值。
    ** 添加状态可以获取默认值。
    ** 修改状态可以设置 modelValue 值
    ** 监听 modelValue 属性,给value 赋值
    */
    value,
    /**
    * 向父组件提交事件
    ** 可以直接绑定到组件的事件,
    ** 也可以套个娃。
    */
    mySubmit
  }
}

export default controlManage

注释与提示

这样写注释可以出现提示,便于调用的时候查看。


002提示.png
003调用提示.png

流程

  • 定义value用于绑定控件值。
  • 添加状态:把默认值设置给value;
  • 修改状态:把v-model设置给value;
  • 监听父组件的v-model,有变化就设置给value。
  • input事件或者其他事件的时候,提交给父组件。

定义url的管理类

我习惯把相关功能写在一个单独的类里面,setup能不写就尽量不写,这样看着清爽。


/**
 * 处理url的管理类
 * * 功能:
 * ** 提交拼接后的完整的url
 * ** 提供绑定控件值、事件
 * ** 修改时自动拆分属性
 * * 参数:
 * ** value: control类的value
 * ** mySubmit: control类的mySubmit,直接就提交了
 */
const urlManage = (value, mySubmit) => {
  // 把url分成三份处理
  const url = reactive({
    http: 'Https://',
    com: '.com',
    value: ''
  })

  // 域名后缀
  const comList = [
    { value: '.com' },
    { value: '.cn' },
    { value: '.net' },
    { value: '.com.cn' },
    { value: '.net.cn' },
    { value: '.org.cn' },
    { value: '.org' },
    { value: '.top' },
    { value: '.vip' },
    { value: '.中国' },
    { value: '.企业' },
    { value: '.公司' },
    { value: '.网络' }
  ]

  // 拆分属性,给url赋值
  watch(() => value.value, (v1, v2) => {
    const arrUrlAll = v1.toLowerCase().split('://')
    console.log('===============================================')
    console.log('父组件:', v1)
    // 判断 ://
    if (arrUrlAll.length === 1) { // 没有http://,直接算作url.value
      url.value = arrUrlAll[0]
    } else if (arrUrlAll.length === 2) {
      url.http = arrUrlAll[0] + '://'
      // 有http://,用 . 拆分后面的
      const arrUrl = arrUrlAll[1].split('.')
      const len = arrUrl.length
      let endPosition = 0
      switch (len) {
        case 1: // 只有一个,直接算作url.value
          url.value = arrUrl[0]
          break
        case 2: // 有两个,一个是url.value,一个是com
          url.value = arrUrl[0]
          url.com = '.' + arrUrl[1]
          break
        default: // 有两个以上,判断两个后缀的情况
          if (arrUrl[len - 1] === 'cn' && (arrUrl[len - 2] === 'com' || arrUrl[len - 2] === 'net' || arrUrl[len - 2] === 'org')) {
            endPosition = len - 2
            url.com = '.' + arrUrl[endPosition] + '.cn'
          } else {
            endPosition = len - 1
            url.com = '.' + arrUrl[endPosition]
          }
          url.value = arrUrl[0]
          for (let i = 1; i < endPosition; i++) {
            url.value += '.' + arrUrl[i]
          }
      }
    }
  })

  // com的查询事件
  const querySearch = (str, cb) => {
    const results = str
      ? comList.filter((item) =>
        item.value.indexOf(str.toLowerCase()) === 0)
      : comList

    // 调用 callback 返回建议列表的数据
    cb(results)
  }

  // url的三个change事件
  const urlSubmit = () => {
    mySubmit(url.http + url.value + url.com)
  }

  return {
    url,
    querySearch,
    urlSubmit
  }
}
  • url
    因为要把url拆分成三份,于是就定义了一个对象。

  • 域名的后缀
    实在太多,这里只把常用的记录列出来了,其他的可以自行填写。


    001域名列表.png

新网的域名,是不是很多?而且还有四个特殊的,.com.cn、.net.cn、.gov.cn、.org.cn,别的都是一个点,这四位两个点。

  • 添加状态
    这个比较简单,把三个分开的部分合并在一起,然后提交就可以了。

  • 修改状态
    这个就有点麻烦,需要把完整的url拆分开分别赋值。
    没想到更好的方法,先用本办法来实现,以后想到更好的再优化。

定义url组件

组件就简单了,引用两个js文件,一拼接就好。

<template>
  <el-input
    :placeholder="meta.placeholder"
    :maxlength="meta.maxlength"
    v-model="url.value"
    @input="urlSubmit"
  >
    <template #prepend><!--前面的选项-->
      <el-select style="width: 90px;"
        v-model="url.http"
        @change="urlSubmit"
        placeholder="请选择">
          <el-option label="Http://" value="Http://"></el-option>
          <el-option label="Https://" value="Https://"></el-option>
      </el-select>
    </template>
    <template #append><!--后面的域名后缀-->
      <el-autocomplete style="width: 100px;"
        class="inline-input"
        v-model="url.com"
        :fetch-suggestions="querySearch"
        placeholder="请输入内容"
        @select="urlSubmit"
        @change="urlSubmit"
      ></el-autocomplete>
    </template>
  </el-input>
</template>

export default {
  name: 'nf-el-from-url',
  props: {
    modelValue: String,
    meta: metaInput
  },
  emits: ['input', 'change', 'blur', 'focus', 'clear'],
  setup (props, context) {
    const { value, mySubmit } = controlManage(props, context)

    // const { url, querySearch, urlSubmit } = urlManage(value, mySubmit)

    return {
      ...urlManage(value, mySubmit)
      // querySearch, // com的筛选的函数
      // url, // url 相关的值
      // urlSubmit // 触发事件
    }
  }
}
  • 模板
    基于element-plus提供的组件修改。

  • return
    一般是在setup里面先把函数引用进来,获取内部对象,然后在返回。
    那么如果没有其他操作的话,可以直接在return里面使用解构的方式直接返给模板。

好了,基本就是这样。简单测试通过。工程化的不方便做在线演示,所以先不做演示了。

源码

https://github.com/naturefwvue/nf-vue-element

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容