range 标准化之获取

range 是用户选择区域的唯一表示方法,存在 w3c 的标准化 range ,以及 ie 特有的 textrange controlrange ,相对于 ie ,w3c 的概念更易于理解,首先简要介绍一下 w3c range.


w3c range


range 用来表示用户的选择区域,这块选择区域由两个边界位置界定,而位置则由其容器以及偏移量构成,称作 container 与 offset .如下是一个简单的位置示例:

 

<p><span>文字</span>^<span>文字</span></p>
 

其中 ^ 表示一个位置,则 container 为父节点 p,offset即为相对于父节点的偏移量为1。需要注意的是当container为元素节点时,其偏移量单元为节点,即从容器的第一个子节点到当前位置处所经历的子节点数。


相应的,container也可以是文字节点,这时container 为 textnode ,而offset则为从该textnode到当前位置所经历的 utf-16 字符个数(意味着,中文和英文计数一样,不是字节计数)。如

 

<p><span>文字</span><span>01234^567</span></p>

 

上例中 container 为 "01234567" 这个文字节点,而offset 则是从该文字节点第一个字符到当前位置所经历的字符个数即5.


ie range


简要介绍一下,具体请查阅 msdn


ie range 没有清晰的容器与偏移量的概念,但是基本思想和 w3c range 一样,具备同等的表达能力,分为 textrange 与 controlrange,包含一系列的方法。


textrange 不是从字面意义上的单纯文本,而是表示用户的选择区域内容(可用其htmlText获取完整内容),其操作方式大多是以文字为单元而不是 dom 树节点。


controlrange 字面意思表示获取选择 控件 ,实际是有些元素(div,img,object...)处于可编辑状态时,经单击可将整个元素选中。



ie 标准化之获取


从上面介绍可见,w3c 的range更规范,更清晰,其 container 与 offset 的概念更直观,当我们需要对range关联dom节点进行操作时,无疑 container ,offset是必不可少的,而 ie range 则没有显示的提供获取这两个关键变量的方法, 前面说过 ie range 其实具备 w3c range 等价的功能,那么就可以结合其提供的一系列方法推导出这两个变量。


范围对象获取:

 

范围对象有两种获取方式:


1.从当前选择区域获得 range ,可调用

 

document.selection.createRange()


方法根据目前选择,返回 TextRange 或 ControlRange 实例。


2.从元素创建 range ,可调用

 

oControlRange = object.createControlRange()
 
oTextRange = object.createTextRange()

 

前一种 之能在 body,element上调用,而后一种 可在大多数元素上调用。调用后则该范围完全覆盖调用元素。相当于 moveToElementText 。

 


textrange 标准化:


首先介绍下用到的几个方法:


collapse :根据参数将结束位置重合到开始位置(true)或开始位置重合到结束位置(false)。


parentElement :获取包围选择区域的元素节点,如下例调用后得到span节点。

 

<span>文^字</span>
 


moveToElementText (Node a) :将选择区域变更为 a ,起始位置为 a 的前后,如作用到如下 span 节点后:

 

^<span>文字</span>^

 

range1.compareEndPoints('XxToYy',range2) :xx,yy 可以为 Start 或 End,取 range1 的 xx 位置和 range2 的 yy 位置比较,根据前后顺序返回-1,1,0表示重合。


range1.setEndPoint("XxToYy",range2) :xx,yy 可以为 Start 或 End,将range1的xx位置设为range2的yy位置。


转化:


有了上面的5个方法就可以开始我们的标准化第一步:获取位置,首先给出操作例子:

 


(绿块表示文字节点,注意:正常手工编写页面情况下不会出现两个相邻的文字节点,这里使用 splitText 强制分离 )


当我们将选择区域collapse后,可能有上述四个位置:1,2,3,4,其中 1,4 相邻元素节点最简单:


1,4位置 标准化:


1.根据 parentElement 得到包含位置的节点 p ,即为该位置的container

2.对container的所有元素子节点,一一验证是否和已知位置相邻,验证方法即为:通过 moveToElementText 新建range包围子节点,再通过 compareEndPoints 比较是否新建 range 的前后位置是否和当前位置重合:

 

range = range.duplicate();
range.collapse(start);
var parent = range.parentElement(),
    siblings = parent.childNodes;
for (var i = 0; i < siblings.length; i++) {
    var child = siblings[i];
    if (child.nodeType == 1) {
        var tr = range.duplicate();
        tr.moveToElementText(child);
        //子元素节点开始位置比较 
        var comparisonStart = tr.compareEndPoints('StartToStart', range),
        //子元素节点结束位置比较 
        comparisonEnd = tr.compareEndPoints('EndToStart', range);
        //开头已经在当前位置后面,没必要继续比了
        if (comparisonStart > 0) break;
        else if (!comparisonStart || comparisonEnd == 1 && comparisonStart == -1) return {
            container: parent,
            offset: i
        };
        else if (!comparisonEnd) return {
            container: parent,
            offset: i + 1
        };
    }
}
 

 

 

2,3位置 标准化:


2 表示位置在两个文字节点之间,container为 p ,由于moveToElementText 无法作用文字节点,则只能另想他法。

3 表示位置处于文本节点中间,此时 container 为文本节点,而 offset 则要数字符数了。



1.当到达 1 位置时,停止。

2.新建range ra,开始位置为 1,结束位置为2或3,取得 ra的所有字符数 ra_textlength,对从位置1开始往右的每个文字节点,从 ra_textlength 中减去其长度(data.length),当 ra_textlength 为0时,代表当前位置为2,而当前经过的文字节点数目即为offset。

当 ra_textlength 为负数时,表示当前位置为3, 当前的文字节点即为位置3 的container,ra_textlength 的上一个值则是offset。



示例:

 

<p id="test"><strong>粗体</strong>普通|文字<i>斜体</i></p>
<script>
document.getElementById("test").childNodes[1].splitText(2);
</script>
 


标准化 demo

 

 

controlrange 标准化

 

controlrange 就很简单了,由 item(index) 方法得到选择元素,结合其parentNode 就可以得到标准化表示了。

 


PS : 关于输入框的范围读取


由于规范规定输入框的选择区域和页面选择区域是分离的,输入框的选择区域有不同的获取方式 (IE 基本相同)。

 

 

<think> 首先,用户的问题是关于在 Vue2 中使用 a-range-picker 获取开始时间和结束时间的方法。用户提到了 Vue2,并且引用了几个相关的引用,这些引用是关于 Vue2 Date Range Picker 和 a-range-picker 的。 从引用中: - 引用[1] 是关于 Vue2 Date Range Picker 的,这是一个基于 Vue2 的日期范围选择器组件。 - 引用[2] 提到了 vue3+antd a-range-picker 的使用,但用户的问题是关于 Vue2 的。 - 引用[3] 是关于 Vue2 Date Range Picker 的项目结构。 - 引用[4] 展示了 a-range-picker 的 onChangeRangeDate 事件,其中获取了开始时间和结束时间。 用户的问题是:“我想查找在Vue2中使用a-range-picker获取开始时间和结束时间的方法”。 在 Vue2 中,a-range-picker 通常来自于 Ant Design Vue 组件库。Ant Design Vue 有 Vue2 和 Vue3 版本,用户指定了 Vue2,所以我需要基于 Vue2 版本的 Ant Design Vue。 关键点: - a-range-picker 是 Ant Design Vue 的 RangePicker 组件,用于选择日期范围。 - 要获取开始时间和结束时间,通常需要处理组件的事件,如 change 事件。 从引用[4]中,有一个示例: ```javascript onChangeRangeDate(value, dateString) { this.startDate = dateString[0]; this.endDate = dateString[1]; } ``` 这里,onChangeRangeDate 事件处理器接收两个参数:value 和 dateString。dateString 是一个数组,其中 dateString[0] 是开始时间,dateString[1] 是结束时间。 在 Vue2 中,使用 Ant Design Vue 的 a-range-picker,步骤大致如下: 1. 在模板中定义 a-range-picker 组件,并绑定事件。 2. 在事件处理器中,获取开始和结束时间。 具体步骤: - 安装 Ant Design Vue for Vue2。 - 在组件中导入和使用 a-range-picker。 - 使用 v-model 或事件来获取值。 在 Vue2 中,Ant Design Vue v1.x 适用于 Vue2。a-range-picker 的文档建议使用 v-model 或 @change 事件来获取值。 标准做法: - 使用 v-model 绑定到数据属性。 - 或者使用 @change 事件来手动处理。 示例代码: ```vue <template> <a-range-picker @change="handleChange" /> </template> <script> export default { methods: { handleChange(date, dateString) { console.log('Selected Time: ', date); console.log('Formatted Selected Time: ', dateString); // dateString is [start, end] this.startDate = dateString[0]; this.endDate = dateString[1]; } } } </script> ``` 在 handleChange 方法中,dateString 是一个数组,包含两个元素:开始日期字符串和结束日期字符串。 或者使用 v-model: ```vue <template> <a-range-picker v-model="dateRange" @change="handleChange" /> </template> <script> export default { data() { return { dateRange: null, // or initial value like [moment(), moment()] if using moment.js }; }, methods: { handleChange(date, dateString) { // dateRange is bound to the value this.startDate = dateString[0]; this.endDate = dateString[1]; } } } </script> ``` 在 v-model 中,dateRange 会是一个数组,包含两个 moment 对象(如果使用了 moment.js)或 Date 对象。 Ant Design Vue 的 RangePicker 默认使用 moment.js 来处理日期。所以,通常需要安装 moment.js。 用户提到了 Vue2,所以我要确保代码适用于 Vue2。 在回答中,我需要: - 使用中文回答。 - 结构清晰,逐步解决问题。 - 确保真实可靠。 - 添加引用标识。 - 生成相关问题。 引用标识:我应该引用用户提供的引用。用户引用[4] 直接相关,所以我可以在回答末尾添加引用标识。 生成相关问题:在回答后,添加 §§相关问题§§。 回答结构: 1. 介绍如何使用 a-range-picker 在 Vue2 中。 2. 提供代码示例。 3. 解释如何获取开始和结束时间。 4. 注意事项(如依赖 moment.js)。 5. 添加引用。 6. 生成相关问题。 完整回答: - 开头:简要介绍。 - 步骤:安装、导入、使用组件、处理事件。 - 代码示例。 - 结尾:总结。 - 引用标识:基于引用[4]。 - 相关问题。 相关问题想法: 1. 如何在 Vue2 中安装 Ant Design Vue? 2. a-range-picker 的其他事件和属性有哪些? 3. 如何处理日期格式? 4. 在 Vue2 中使用 moment.js 的注意事项。 最终回答格式: - 使用中文。 - 代码块用 ``` 包裹。 - 末尾添加引用标识。 </think> 在 Vue2 中使用 Ant Design Vue 的 `a-range-picker` 组件获取开始时间和结束时间,主要通过处理组件的 `change` 事件实现。以下是详细步骤和代码示例,基于 Vue2 和 Ant Design Vue v1.x(适用于 Vue2)。 ### 步骤说明 1. **安装依赖** 确保项目中已安装 Ant Design Vue 和 moment.js(用于日期处理): ```bash npm install ant-design-vue@1.7.8 moment --save # 指定适用于 Vue2 的版本 ``` 2. **引入组件** 在 Vue 组件中导入 `a-range-picker` 和 moment.js: ```vue <template> <div> <a-range-picker @change="handleChange" :show-time="false" <!-- 可选配置,是否显示时间选择 --> /> <p>开始时间:{{ startDate }}</p> <p>结束时间:{{ endDate }}</p> </div> </template> <script> import moment from 'moment'; import { DatePicker } from 'ant-design-vue'; export default { components: { 'a-range-picker': DatePicker.RangePicker, }, data() { return { startDate: null, // 存储开始时间 endDate: null, // 存储结束时间 }; }, methods: { // 处理 change 事件 handleChange(date, dateString) { // dateString 是数组,[0]为开始时间,[1]为结束时间 this.startDate = dateString[0]; // 例如 "2023-10-01" this.endDate = dateString[1]; // 例如 "2023-10-07" console.log('开始时间:', this.startDate, '结束时间:', this.endDate); } } }; </script> ``` 3. **关键事件说明** - **`@change` 事件**:当用户选择日期范围时触发,回调参数为: - `date`: 包含 moment 对象的数组(需 moment.js 支持)。 - `dateString`: 格式化后的日期字符串数组,`dateString[0]` 是开始时间,`dateString[1]` 是结束时间(例如 `["2023-10-01", "2023-10-07"]`)。 - 直接使用 `dateString` 是最简单的方式,无需额外处理日期格式。 ### 注意事项 - **日期格式**:默认返回格式为 `YYYY-MM-DD`。如需自定义格式,使用 `format` 属性: ```vue <a-range-picker @change="handleChange" format="YYYY/MM/DD" <!-- 自定义格式 --> /> ``` - **禁用日期**:可通过 `:disabled-date` 属性限制可选范围(引用[4]示例)。 - **Vue2 兼容性**:确保使用 Ant Design Vue v1.x(如 `1.7.8`),v2.x 及以上仅支持 Vue3。 ### 完整示例 ```vue <template> <div> <a-range-picker @change="handleChange" :show-time="false" format="YYYY-MM-DD" /> <div v-if="startDate && endDate"> 开始时间:{{ startDate }},结束时间:{{ endDate }} </div> </div> </template> <script> import moment from 'moment'; import { DatePicker } from 'ant-design-vue'; export default { components: { 'a-range-picker': DatePicker.RangePicker, }, data() { return { startDate: null, endDate: null, }; }, methods: { handleChange(date, dateString) { this.startDate = dateString[0]; this.endDate = dateString[1]; } } }; </script> ``` ### 引用说明 此方法基于 Ant Design Vue 的 `a-range-picker` 事件处理机制,通过 `change` 事件直接获取格式化后的日期字符串(引用[4])[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值