官网有一个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
注释与提示
这样写注释可以出现提示,便于调用的时候查看。
流程
- 定义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拆分成三份,于是就定义了一个对象。-
域名的后缀
实在太多,这里只把常用的记录列出来了,其他的可以自行填写。
新网的域名,是不是很多?而且还有四个特殊的,.com.cn、.net.cn、.gov.cn、.org.cn,别的都是一个点,这四位两个点。
添加状态
这个比较简单,把三个分开的部分合并在一起,然后提交就可以了。修改状态
这个就有点麻烦,需要把完整的url拆分开分别赋值。
没想到更好的方法,先用本办法来实现,以后想到更好的再优化。
定义url组件
组件就简单了,引用两个js文件,一拼接就好。
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