做空调的网站,东平建设局网站,网站开发的广告,网站正在紧急建设中v-model 本质是 prop 和 事件监听 的语法糖。 通过 prop 实现 数据 - 视图 的单向数据流#xff1b;通过监听 change 或 input 事件实现 视图 - 数据 的单向数据流。 /*** v-model 的实现* 注册了 created 和 beforeUpdate 两个钩子函数*/
const VModelText {/*** cr…v-model 本质是 prop 和 事件监听 的语法糖。 通过 prop 实现 数据 - 视图 的单向数据流通过监听 change 或 input 事件实现 视图 - 数据 的单向数据流。 /*** v-model 的实现* 注册了 created 和 beforeUpdate 两个钩子函数*/
const VModelText {/*** created 钩子函数* param {Object} el - 节点对象* param {Object} binding - binding 对象* param {Object} vnode - 虚拟节点对象* created 主要做了 3 件事* 1、将 js 对象的 value 赋值为元素的 value 属性* 2、通过 getModelAssigner 方法获取 props 中的 onUpdate:modelValue 属性赋值给元素的 _assign 属性* 3、通过 addEventListener 监听 input 标签的事件*/created(el, { value, modifiers: { lazy, trim, number } }, vnode) {// 1、将 js 对象的 value 赋值为元素的 value 属性数据 - 视图的单向数据流el.value value null ? : value// 2、通过 getModelAssigner 方法获取 props 中的 onUpdate:modelValue 属性赋值给元素的 _assign 属性el._assign getModelAssigner(vnode)// 判断是否配置了 number 或 元素的 type 为 numberconst castToNumber number || el.type number// 3、通过 addEventListener 监听 input 标签的事件// 根据 lazy 决定监听元素的 change 或 input 事件(change | input)addEventListener(el, lazy ? change : input, e {if (e.target.composing) return// 获取元素的新值let domValue el.value// 如果配置了 trim则调用 String.trim() 清除首尾空格if (trim) {domValue domValue.trim()}// 如果配置了 number 或元素的 type 为 number则转换成 number 后再赋值给元素else if (castToNumber) {domValue toNumber(domValue)}// 更新数据el._assign(domValue)})// 如果配置了 trim则调用 String.trim() 清除首尾空格if (trim) {addEventListener(el, change, () {el.value el.value.trim()})}// 如果没有配置 lazy则添加两个事件对中文输入法输入进行监听if (!lazy) {addEventListener(el, compositionstart, onCompositionStart)addEventListener(el, compositionend, onCompositionEnd)}},/*** beforeUpdata 钩子函数* param {Object} el - 节点对象* param {Object} binding - binding 对象* param {Object} vnode - 虚拟节点对象*/beforeUpdate(el, { value, modifiers: { trim, number } }, vnode) {el._assign getModelAssigner(vnode)if (document.activeElement el) {// 如果配置了 trim则将元素的值通过 String.trim() 清除首尾空格和再赋值给数据if (trim el.value.trim() value) return// 如果配置了 number 或 元素的 type 为 number则将元素的值转换为 number 再赋值给数据if ((number || el.type number) toNumber(el.value) value) return}const newValue value null ? : value// 更新前判断新旧值是否相同如果不同则把数据更新到 DOM 上if (el.value ! newValue) {el.value newValue}}
}/*** 获取 model 分配器*/
const getModelAssigner (vnode) {const fn vnode.props[onUpdate:modelValue]return isArray(fn) ? value invokeArrayFns(fn, value) : fn
}/*** 中文输入法触发的事件*/
function onCompositionStart(e) {e.target.composing true
}/*** 中文输入法中确定输入的数据后触发的事件*/
function onCompositionEnd(e) {const target e.targetif (target.composing) {target.composing false// 手动触发 input 事件进行赋值trigger(target, input)}
}