import React, { Component } from 'react';
import PropTypes from 'prop-types'; const reduceTargetKeys = (target, keys, predicate) => Object.keys(target).reduce(predicate, {}); const omit = (target = {}, keys = []) =>
reduceTargetKeys(target, keys, (acc, key) => keys.some(omitKey => omitKey === key) ? acc : { ...acc, [key]: target[key] }); const pick = (target = {}, keys = []) =>
reduceTargetKeys(target, keys, (acc, key) => keys.some(pickKey => pickKey === key) ? { ...acc, [key]: target[key] } : acc); const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b); const propTypes = {
content: PropTypes.string,
editable: PropTypes.bool,
focus: PropTypes.bool,
maxLength: PropTypes.number,
multiLine: PropTypes.bool,
sanitise: PropTypes.bool,
caretPosition: PropTypes.oneOf(['start', 'end']),
tagName: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), // The element to make contenteditable. Takes an element string ('div', 'span', 'h1') or a styled component
innerRef: PropTypes.func,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
onPaste: PropTypes.func,
onChange: PropTypes.func,
styled: PropTypes.bool, // If element is a styled component (uses innerRef instead of ref)
}; const defaultProps = {
content: '',
editable: true,
focus: false,
maxLength: Infinity,
multiLine: false,
sanitise: true,
caretPosition: null,
tagName: 'div',
innerRef: () => { },
onBlur: () => { },
onFocus: () => { },
onKeyDown: () => { },
onPaste: () => { },
onChange: () => { },
styled: false,
}; class ContentEditable extends Component {
constructor(props) {
super(); this.state = {
value: props.content,
isFocused: false,
};
} componentDidMount() {
this.setFocus();
this.setCaret();
} componentWillReceiveProps(nextProps) {
if (nextProps.content !== this.sanitiseValue(this.state.value)) {
this.setState({ value: nextProps.content }, () => {
if (!this.state.isFocused) this.forceUpdate();
});
}
} shouldComponentUpdate(nextProps) {
const propKeys = Object.keys(nextProps).filter(key => key !== 'content');
return !isEqual(pick(nextProps, propKeys), pick(this.props, propKeys));
} componentDidUpdate() {
this.setFocus();
this.setCaret();
} setFocus = () => {
if (this.props.focus && this._element) {
this._element.focus();
}
}; setCaret = () => {
const { caretPosition } = this.props; if (caretPosition && this._element) {
const { value } = this.state;
const offset = value.length && caretPosition === 'end' ? 1 : 0;
const range = document.createRange();
const selection = window.getSelection();
range.setStart(this._element, offset);
range.collapse(true); selection.removeAllRanges();
selection.addRange(range);
}
}; sanitiseValue(val) {
const { maxLength, multiLine, sanitise } = this.props; if (!sanitise) {
return val;
} // replace encoded spaces
let value = val.replace(/ /, ' ').replace(/[\u00a0\u2000-\u200b\u2028-\u2029\u202e-\u202f\u3000]/g, ' '); if (multiLine) {
// replace any 2+ character whitespace (other than new lines) with a single space
value = value.replace(/[\t\v\f\r ]+/g, ' ');
} else {
value = value.replace(/\s+/g, ' ');
} return value
.split('\n')
.map(line => line.trim())
.join('\n')
.replace(/\n{3,}/g, '\n\n') // replace 3+ line breaks with two
.trim()
.substr(0, maxLength);
} _onChange = ev => {
const { sanitise } = this.props;
const rawValue = this._element.innerText;
const value = sanitise ? this.sanitiseValue(rawValue) : rawValue; if (this.state.value !== value) {
this.setState({ value: rawValue }, () => {
this.props.onChange(ev, value);
});
}
}; _onPaste = ev => {
const { maxLength } = this.props; ev.preventDefault();
const text = ev.clipboardData.getData('text').substr(0, maxLength);
document.execCommand('insertText', false, text); this.props.onPaste(ev);
}; _onBlur = ev => {
const { sanitise } = this.props;
const rawValue = this._element.innerText;
const value = sanitise ? this.sanitiseValue(rawValue) : rawValue; // We finally set the state to the sanitised version (rather than the `rawValue`) because we're blurring the field.
this.setState({
value,
isFocused: false,
}, () => {
this.props.onChange(ev, value);
this.forceUpdate();
}); this.props.onBlur(ev);
}; _onFocus = ev => {
this.setState({
isFocused: true,
});
this.props.onFocus(ev);
}; _onKeyDown = ev => {
const { maxLength, multiLine } = this.props;
const value = this._element.innerText; // return key
if (!multiLine && ev.keyCode === 13) {
ev.preventDefault();
ev.currentTarget.blur();
// Call onKeyUp directly as ev.preventDefault() means that it will not be called
this._onKeyUp(ev);
} // Ensure we don't exceed `maxLength` (keycode 8 === backspace)
if (maxLength && !ev.metaKey && ev.which !== 8 && value.replace(/\s\s/g, ' ').length >= maxLength) {
ev.preventDefault();
// Call onKeyUp directly as ev.preventDefault() means that it will not be called
this._onKeyUp(ev);
}
}; _onKeyUp = ev => {
// Call prop.onKeyDown callback from the onKeyUp event to mitigate both of these issues:
// Access to Synthetic event: https://github.com/ashleyw/react-sane-contenteditable/issues/14
// Current value onKeyDown: https://github.com/ashleyw/react-sane-contenteditable/pull/6
// this._onKeyDown can't be moved in it's entirety to onKeyUp as we lose the opportunity to preventDefault
this.props.onKeyDown(ev, this._element.innerText);
}; render() {
const { tagName: Element, content, editable, styled, ...props } = this.props; return (
<Element
{...omit(props, Object.keys(propTypes))}
{...(styled
? {
innerRef: c => {
this._element = c;
props.innerRef(c);
},
}
: {
ref: c => {
this._element = c;
props.innerRef(c);
},
})}
style={{ minHeight: '0.28rem', minWidth: '100%', display: 'inline-block', whiteSpace: 'pre-wrap', wordWrap: 'break-word', wordBreak: 'break-all', ...props.style }}
contentEditable={editable}
key={Date()}
dangerouslySetInnerHTML={{ __html: this.state.value }}
onBlur={this._onBlur}
onFocus={this._onFocus}
onInput={this._onChange}
onKeyDown={this._onKeyDown}
onKeyUp={this._onKeyUp}
onPaste={this._onPaste}
/>
);
}
} ContentEditable.propTypes = propTypes;
ContentEditable.defaultProps = defaultProps; export default ContentEditable;

自适应高度文本框 react contenteditable的更多相关文章

  1. htm5 手机自适应问题 文本框被激活(获取焦点)时,页面会放大至原来尺寸。

    加上这句话就ok啦 <meta name="viewport" content="width=device-width, initial-scale=1.0, mi ...

  2. html5 textarea 文本框根据输入内容自适应高度

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  3. jquery文本框textarea自适应高度

    浏览器中默认的文本框是不能根据内容的增多变高,只能固定高度有滚动条,体验不是很好,找了很多方法兼容都不行,总算找到个兼容良好的方法: <body> <textarea id=&quo ...

  4. 自适应高度输入框(contenteditable/textarea)

      一.用div模拟textarea div模拟输入域可以根据输入内容自动伸缩,而input和textarea输入内容较多时,高度固定,内容会显示不全. 1.坑1(IOS端无法输入) 在取消全局默认样 ...

  5. Jquery实现textarea根据文本内容自适应高度

    本文给大家分享的是Jquery实现textarea根据文本内容自适应高度,这些在平时的项目中挺实用的,所以抽空封装了一个文本框根据输入内容自适应高度的插件,这里推荐给小伙伴们. autoTextare ...

  6. Jquery实现 TextArea 文本框根据输入内容自动适应高度

    原文 Jquery实现 TextArea 文本框根据输入内容自动适应高度 在玩微博的时候我们可能会注意到一个细节就是不管是新浪微博还是腾讯微博在转发和评论的时候给你的默认文本框的高度都不会很高,这可能 ...

  7. JS案例 - 可自动伸缩高度的textarea文本框

    文本框的默认现象: textarea如果设置cols和rows来规定textarea的尺寸,那么textarea的默认宽高是这俩属性设置的值,可以通过鼠标拖拽缩放文本框的尺寸. textarea如果设 ...

  8. [Swift通天遁地]二、表格表单-(12)设置表单文字对齐方式以及自适应高度的文本区域TextArea

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  9. iOS之自动调节输入文本框的高度

    //自动调节输入文本框的高度 - (void)textViewDidChange:(UITableView *)textView{ float height; if ([[[UIDevice curr ...

随机推荐

  1. Qt编写控件属性设计器9-数据库采集

    一.前言 数据库作为数据源,在很多组态软件中使用非常多,指定数据库类型,填写好数据库连接信息,指定对应的数据库表和字段,采集间隔,程序按照采集间隔自动采集数据库数据,绑定到界面上的控件赋值显示即可.使 ...

  2. Day5作业,商城+ATM机+后台管理

    晚来了....东西太多,需要写的blog内容太多,re讲的渣渣,不明白为什么oldboy经常换老师,吐槽下吧,真心不爱了.... github地址在这:https://github.com/ccorz ...

  3. PAT 甲级 1054 The Dominant Color (20 分)(简单题)

    1054 The Dominant Color (20 分)   Behind the scenes in the computer's memory, color is always talked ...

  4. ORM连表操作

    连表操作分为以下三种情景: 一对多:models.ForeignKey(其他表) 多对多:models.ManyToManyField(其他表) 一对一:models.OneToOneField(其他 ...

  5. python面向对象之封装,继承,多态

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容.在python的类中,封装即通过__init__函数将数据赋给对应的变量进行保存,便于其他地方使用 所以,在使用面向对象的封装特 ...

  6. iOS-app发布新版本步骤

    1

  7. 【c# 学习笔记】面向对象编程的应用

    在平时的开发过程中,面向对象编程的应用肯定必不可少.但前面的内容只是单独介绍了类.面向对象思想和接口,那么我们怎么在平时工作中来应用他们来实现面向对象编程呢? 如果你想设计一个Dog类,有了类的概念后 ...

  8. Java中让fastJson识别Colloction和Map中的泛型类

    由于fastJson的高效性,最近采用fastJson来做序列化并存储数据,但出现了一个麻烦的问题,如果将Map<K,V>这样的类型序列化,反序列化就会不尽人意,有以下尝试: 使用JSON ...

  9. IIC挂死问题解决过程

    0.环境:arm CPU 带有IIC控制器作为slave端,带有调试串口. 1.bug表现:IIC slave 在系统启动后概率挂死,导致master无法detect到slave. 猜测1:认为IIC ...

  10. linux系统下,在用户空间应用程序中模拟发送系统键盘事件

    Linux 有自己的 input 子系统,可以统一管理鼠标和键盘事件. 如果想模拟键盘事件,但是系统没有键盘设备该如何是好? 基于输入子系统实现的 input 可以方便的在用户空间模拟鼠标和键盘事件. ...