/**
input, select, textarea这几个元素如果指定了value/checked的**状态属性**,就会包装成受控组件或非受控组件
受控组件是指,用户除了为它指定**状态属性**,还为它指定了onChange/onInput/disabled等用于控制此状态属性
变动的属性
反之,它就是非受控组件,非受控组件会在框架内部添加一些事件,阻止**状态属性**被用户的行为改变,只能被setState改变
*/
import { typeNumber } from "./util"; export function processFormElement(vnode, dom, props) {
var domType = dom.type;
var duplexType = duplexMap[domType];
if (duplexType) {
var data = duplexData[duplexType];
var duplexProp = data[0];
var keys = data[1];
var eventName = data[2];
if (duplexProp in props && !hasOtherControllProperty(props, keys)) {
// eslint-disable-next-line
console.warn(`你为${vnode.type}[type=${domType}]元素指定了${duplexProp}属性,
但是没有提供另外的${ Object.keys(keys)}来控制${duplexProp}属性的变化
那么它即为一个非受控组件,用户无法通过输入改变元素的${duplexProp}值`);
dom[eventName] = data[3];
}
if (duplexType === 3) {
postUpdateSelectedOptions(vnode);
}
}
} function hasOtherControllProperty(props, keys) {
for (var key in props) {
if (keys[key]) {
return true;
}
}
}
var duplexMap = {
color: 1,
date: 1,
datetime: 1,
"datetime-local": 1,
email: 1,
month: 1,
number: 1,
password: 1,
range: 1,
search: 1,
tel: 1,
text: 1,
time: 1,
url: 1,
week: 1,
textarea: 1,
checkbox: 2,
radio: 2,
"select-one": 3,
"select-multiple": 3
}; function preventUserInput(e) {
var target = e.target;
var name = e.type === "textarea" ? "innerHTML" : "value";
target[name] = target._lastValue;
} function preventUserClick(e) {
e.preventDefault();
} function preventUserChange(e) {
var target = e.target;
var value = target._lastValue;
var options = target.options;
if (target.multiple) { updateOptionsMore(options, options.length, value);
} else {
updateOptionsOne(options, options.length, value);
}
} var duplexData = {
1: [
"value",
{
onChange: 1,
onInput: 1,
readOnly: 1,
disabled: 1
},
"oninput",
preventUserInput
],
2: [
"checked",
{
onChange: 1,
onClick: 1,
readOnly: 1,
disabled: 1
},
"onclick",
preventUserClick
],
3: [
"value",
{
onChange: 1,
disabled: 1
},
"onchange",
preventUserChange
]
}; export function postUpdateSelectedOptions(vnode) {
var props = vnode.props,
multiple = !!props.multiple,
value =
typeNumber(props.value) > 1
? props.value
: typeNumber(props.defaultValue) > 1
? props.defaultValue
: multiple ? [] : "",
options = [];
collectOptions(vnode, props, options);
if (multiple) {
updateOptionsMore(options, options.length, value);
} else {
updateOptionsOne(options, options.length, value);
}
} /**
* 收集虚拟DOM select下面的options元素,如果是真实DOM直接用select.options
*
* @param {VNode} vnode
* @param {any} props
* @param {Array} ret
*/
function collectOptions(vnode, props, ret) {
var arr = props.children;
for (var i = 0, n = arr.length; i < n; i++) {
var el = arr[i];
if (el.type === "option") {
ret.push(el);
} else if (el.type === "optgroup") {
collectOptions(el, el.props, ret);
}
}
} function updateOptionsOne(options, n, propValue) {
var selectedValue = "" + propValue;
for (let i = 0; i < n; i++) {
let option = options[i];
let value = getOptionValue(option, option.props);
if (value === selectedValue) {
getOptionSelected(option, true);
return;
}
}
if (n) {
getOptionSelected(options[0], true);
}
} function updateOptionsMore(options, n, propValue) {
var selectedValue = {};
try {
for (let i = 0; i < propValue.length; i++) {
selectedValue["&" + propValue[i]] = true;
}
} catch (e) {
/* istanbul ignore next */
console.warn('<select multiple="true"> 的value应该对应一个字符串数组'); // eslint-disable-line
}
for (let i = 0; i < n; i++) {
let option = options[i];
let value = getOptionValue(option, option.props);
let selected = selectedValue.hasOwnProperty("&" + value);
getOptionSelected(option, selected);
}
} function getOptionValue(option, props) {
if (!props) {
return getDOMOptionValue(option);
}
//这里在1.1.1改动过, props.value === undefined ? props.children[0].text : props.value;
return props.value === undefined ? props.children : props.value;
} function getDOMOptionValue(node) {
if (node.hasAttribute && node.hasAttribute("value")) {
return node.getAttribute("value");
}
var attr = node.getAttributeNode("value");
if (attr && attr.specified) {
return attr.value;
}
return node.innerHTML.trim();
} function getOptionSelected(option, selected) {
var dom = option._hostNode || option;
dom.selected = selected;
}

anu - controlledComponent的更多相关文章

  1. 发布高性能迷你React框架anu

    anu, 读作[安努],原意为苏美尔的主神. anu是我继avalon之后又一个新框架(github仓库为https://github.com/RubyLouvre/anu, 欢迎加星与试用) 此框架 ...

  2. 利用React/anu编写一个弹出层

    本文将一步步介绍如何使用React或anu创建 一个弹出层. React时代,代码都是要经过编译的,我们很多时间都耗在babel与webpack上.因此本文也介绍如何玩webpack与babel. 我 ...

  3. 高性能迷你React框架anu在低版本IE的实践

    理想是丰满的,现实是骨感的,react早期的版本虽然号称支持IE8,但是页面总会不自觉切换到奇异模式下,导致报错.因此必须让react连IE6,7都支持,这才是最安全.但React本身并不支持IE6, ...

  4. anu小程序快速入门

    众所周知,微信推出小程序以来,可谓火遍大江南北,就像当前互联网兴起时,大家忙着抢域名与开私人博客一样.小程序之所以这么火,是因为微信拥有庞大的用户量,并且腾讯帮你搞定后台问题及众多功能问题(如分享,支 ...

  5. Codeforces Round #618 (Div. 2)C. Anu Has a Function

    Anu has created her own function ff : f(x,y)=(x|y)−y where || denotes the bitwise OR operation. For ...

  6. React/anu实现Touchable

    在RN中有一个叫Touchable 的组件,这里我们重演如何实现它. Touchable存在的意义是屏蔽click的问题.移动端与手机的click 在一些浏览器是有差异,比如说著名的300ms延迟. ...

  7. React/anu实现弹出层2

    这次是使用了一个比较罕见的APIReactDOM.unstable_renderSubtreeIntoContainer,ReactDOM.unstable_renderSubtreeIntoCont ...

  8. anu - browser

    import { oneObject, recyclables, typeNumber } from "./util"; //用于后端的元素节点 export function D ...

  9. anu - reactIE

    import { options } from "./util"; import { Children } from "./Children"; import ...

随机推荐

  1. Unity3D学习笔记(五):坐标系、向量、3D数学

    Unity复习 using System.Collections; using System.Collections.Generic; using UnityEngine; public class ...

  2. C# 新Form各事件执行顺序

    1. 构造函数 2. Load() 3. Show() 4. Acticated()

  3. mini Linux制作过程(25/01)

    Mini Linux: 启动流程: 参考:https://blog.csdn.net/gatieme/article/details/50914250 https://linux.cn/article ...

  4. 学习mybatis-3 step by step 篇三

    动态 SQL if choose (when, otherwise) trim (where, set) foreach 动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分.比如: ...

  5. (02) 任务(Jobs)和触发器(Triggers)

    Quart 的 API Quartz API 中的关键接口和类如下: IScheduler-与调度器(scheduler)进行交互的主要 API: IJob-被组件继承和实现,由调度器来执行的接口: ...

  6. shell 字符串运算符

    字符串运算符 下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg": 运算符 说明 举例 = 检测两个字符串是否相等,相等返回 ...

  7. MyEclipse2014 优化设置

    1.指定本机java环境 Windows-->preferences-->java-->Insetallel JREs 右侧 单击ADD standard VM-->Next ...

  8. Python -- Scrapy 架构概览

    架构概览 本文档介绍了Scrapy架构及其组件之间的交互. 概述 接下来的图表展现了Scrapy的架构,包括组件及在系统中发生的数据流的概览(绿色箭头所示). 下面对每个组件都做了简单介绍,并给出了详 ...

  9. js中如何访问对象和数组

    js中如何访问对象和数组 一.总结 一句话总结:js访问对象点和中括号,访问数组的话就是中括号 对象 . [] 数组 [] 1.js访问对象的两种方式? . [] 可以使用下面两种方式访问对象的属性和 ...

  10. php 7.2 安装 mcrypt 扩展: mcrypt 扩展从 php 7.1.0 开始废弃;自 php 7.2.0 起,会移到 pecl

    升级 php 7.2 后,使用微信提供的加解密代码时,提示 call to undefined function mcrypt_module_open() :大脑疯狂运转1秒钟后,得出结论:php 7 ...