div可编辑事件 react_react div可编辑时placeholder - CSDN
  • React官方介绍可编辑Div的资料比较少,方式二在所有的资料中都没找到,是通过特殊的方法实现的。 dangerouslySetInnerHTML 是React专用的属性 <div id="context" contentEditable={true} ...

    React官方介绍可编辑Div的资料比较少,方式二在所有的资料中都没找到,是通过特殊的方法实现的。

    dangerouslySetInnerHTML 是React专用的属性

    <div id="context" contentEditable={true} dangerouslySetInnerHTML={{__html: this.state.inputValueHtml}}></div>

    获取焦点方式1

    document.querySelector('#context').focus();

    PS:以上方法只会在句首获取焦点

    获取焦点方式2

    let srcObj = document.querySelector('#context');
    let selection = window.getSelection();
    let range = document.createRange();
    range.selectNodeContents(srcObj);
    selection.removeAllRanges();
    selection.addRange(range);
    range.setStart(srcObj, 1);
    range.setEnd(srcObj, 1);

    以上方式会在最后句尾获取焦点

    展开全文
  • 输入的时候完全没有问题,但是在修改涉及到使用其渲染的时候,就会把字符串渲染出来,而不是渲染原生的标签对 渲染时要使用 ...div ref="add" contenteditable="true" className={styles.areaBox}>&l...

    输入的时候完全没有问题,但是在修改涉及到使用其渲染的时候,就会把字符串渲染出来,而不是渲染原生的标签对

    渲染时要使用 dangerouslySetInnerHTML属性,并且传入对象进行渲染

     

    render函数return部分:

         <div ref="add" contenteditable="true" className={styles.areaBox}></div>
    
            <button onClick={(e) => { this.test(e) }}></button>
    
            <div contenteditable="true" dangerouslySetInnerHTML={{__html: `${this.state.add}`}} className={styles.areaBox}></div>

     

    方法部分 :

     test = () => {
        this.setState({
          add: this.refs.add.innerHTML
        })
      }

     

    状态部分 :

     constructor(props) {
        super(props);
    this.state = { add: "" }
    }

     


     

    转载于:https://www.cnblogs.com/opacity-m/p/8947788.html

    展开全文
  • 可编辑div组件

    前言

    最近接到一个需求,要实现一个能输入带颜色的文字的输入框,可以渲染html字符串。立刻就想到了HTML的contenteditable属性。在HTML中,任何元素都可以编辑,只要将元素的contenteditable属性设置为true。

    环境

    • vue2.5
    • webpack3.6

    分析需要的功能

    • 提供快捷键
    • 提供input、change、focus、blur事件
    • v-model指令可以绑定该组件
    • 禁用功能
    • 清空输入的内容

    代码如下

    EventUtil是封装的跨浏览器的事件对象。

    <!--BaseEditDiv.vue-->
    <template>
      <div
        class="base-edit-div"
        :style="{'-webkit-user-modify': disabled ? 'read-only' : '', '-moz-user-modify': disabled ? 'read-only' : '', 'overflow-x': disabled ? 'hidden' : '', 'height' : disabled && !text ? '35px' : '100%'}"
        contenteditable="true"
        @focus="$emit('focus', $event)"
        @click="$emit('click')"
        @blur="$emit('blur', $event)"
        @keydown="$emit('keydown', $event)"
        @keyup="$emit('keyup', $event)"
        @input="domInput"
      ></div>
    </template>
    
    <script>
    import EventUtil from './EventUtil.js'
    export default {
      props: {
        // 默认值
        text: {
          type: String,
          default: ''
        },
        disabled: {
          type: Boolean,
          default: false
        }
      },
      mounted () {
        // 组件初始化,对innerHTML赋值
        this.$el.innerHTML = this.text
        // 一旦div的dom发生插入值的操作,调用domChange()方法传递值至父组件
        EventUtil.addHandler(this.$el, 'DOMNodeInserted', this.domChange)
      },
      beforeDestroy () {
        // 销毁
        EventUtil.removeHandler(this.$el, 'DOMNodeInserted', this.domChange)
      },
      methods: {
        domChange (event) {
          this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
        },
        emptyInnerHTML () {
          this.$el.innerHTML = ''
          this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
        },
        domInput (event) {
          this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
        }
      }
    }
    </script>
    
    <style lang="less" scoped>
    .base-edit-div{
      position: relative;
      outline: none;
      border: 1px solid #EAECF1;
      padding: 5px 26px 5px 12px;
      border-radius: 2px;
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      overflow: auto;
      word-break: break-all;
      user-select: text;
      text-align: left;
    }
    </style>
    

    使用

    <!--HelloWorld.vue-->
    <template>
      <div class="content">
        <base-edit-div
          class="beautiful"
          :text="checkHtml"
          v-model="checkHtml"
        >
        </base-edit-div>
      </div>
    </template>
    
    <script>
    import BaseEditDiv from './BaseEditDiv'
    export default {
      components: {
        BaseEditDiv
      },
      data () {
        return {
          checkHtml: '<b style="color:red;font-weight:normal" contenteditable="false">[噪音]</b>\r'
        }
      }
    }
    </script>
    
    <style lang="less" scoped>
      .content{
    	margin: 50px auto;
        .beautiful{
          width: 300px;
          box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
          border-radius: 4px;
          border: 1px solid #ebeef5;
          background-color: #fff;
          overflow: hidden;
          color: #303133;
          transition: .3s;
        }
      }
    </style>
    

    效果如下

    在这里插入图片描述

    展开全文
  • 在实际项目中会涉及到很多有关表格的...3.在没有数据情况下,增加可编辑的表格,进行数据维护。 以下展示的代码,包含了上面提及的情况,可直接复制代码运行 代码分布 ├── table/ │ ├── index.js │ ├─...

    在实际项目中会涉及到很多有关表格的问题,而不仅仅是将数据渲染在页面上。
    1.表格中的数据可以编辑,input框,下拉框等。
    2.有时候对输入的数据也会有限制,如保留两位小数或者输入正整数等。
    3.在没有数据情况下,增加可编辑的表格,进行数据维护。

    以下展示的代码,包含了上面提及的情况,可直接复制代码运行

    (1) 在无数据的情况下,新增按钮可以点击,点击新增按钮,一次最多增加3行可编辑行,新增之后,按钮为禁止状态

    在这里插入图片描述

    (2) 有数据的情况下,数据渲染在页面上,表格可编辑。(默认最多显示3行,如果数据不足3组,可判断一下补充至3行,这种情况下面代码中不包含)

    在这里插入图片描述

    • 代码分布
    	├── table/                                                                   
    	│     ├── index.less                    
    	│     ├── state.js                         
    	│     ├── addTable.js                              
    	│     ├──mock.json    
    
    • addTable.js table组件部分
    import React from 'react'
    import { observer } from 'mobx-react'
    import { Table, Input, Select, Form, Button } from 'antd'
    import $state from './state'
    
    const { Option } = Select
    const { Item } = Form
    @observer
    class ThirdTable extends React.Component {
      constructor(props) {
        super(props)
        this.state = {}
      }
    
      componentDidMount() {
        $state.queryDetails()
        this.isDisable()
      }
      componentDidUpdate() {
        this.isDisable()
      }
    
      //判断按钮是否是禁止状态
      isDisable = () => {
        let source = [];
        source = $state.topThreeDTO || []
    
        if (!source.length) {
          $state.isDisableFlag1 = false
        } else {
          $state.isDisableFlag1 = true
        }
        //优化后为下面这样
        $state.isDisableFlag1=!!source.length
      }
    
      init = () => {
        const { getFieldDecorator } = this.props.form
        const projectArr = [
          { name: "绿州", num: "100" },
          { name: "长岛", num: "101" },
          { name: "紫荆", num: "102" }
        ]
    
        this.columns = [
          {
            title: '排名',
            dataIndex: 'orderNum',
          },
          {
            title: '项目名称',
            dataIndex: 'projectName',
            width: '40%',
            render: (text, record) => {
              console.log(`projectName.${record.orderNum}`)//projectName.1 需要保证唯一性
              return <Item>
                {     
                  getFieldDecorator(`projectName.${record.orderNum}`, {
                    initialValue: text && text.num
                  })
                    (
                      <Select>
                        {
                          projectArr.length > 0 && projectArr.map((item, index) => {
                            return <Option style={{width:120}} value={item.num} key={index}>			{item.name}</Option>
                          })
                        }
                      </Select>
                    )
                }
              </Item>
            }
          },
          {
            title: '均价(元/㎡)',
            dataIndex: 'averagePrice',
            width: '40%',
            render: (text, record) => {
              return <Item >
                {
                  getFieldDecorator(`averagePrice.${record.orderNum}`, {
                    rules: [{
                      pattern: new RegExp(/^[1-9]\d*$/),
                      message: '请输入正整数!'
                    }],
                    /*rules: [{
                        pattern: new RegExp(/^(([1-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2})))$/),
    
                        message: '小数点后最多保留两位小数!'
                      }],*/
                    initialValue: text
                  })
                    (
                      <Input />
                    )
                }
              </Item>
            }
          }
        ];
      }
      //新增表格
      handleAddRow = () => {
        const newData = [
          {
            orderNum: '1',
            projectName: { name: "", num: "" },
            averagePrice: "",
          },
          {
            orderNum: '2',
            projectName: { name: "", num: "" },
            averagePrice: "",
          },
          {
            orderNum: '3',
            projectName: { name: "", num: "" },
            averagePrice: "",
          }
        ]
    
        $state.topThreeDTO = newData
        $state.isDisableFlag1 = true
      }
      render() {
        this.init()
        return (
        //data={{ flag: $state.renderFlag }} 强制渲染表格的一种方法
          <div data={{ flag: $state.renderFlag }}>
            <h1 className='table-title'>
              前三名
              </h1>
            <Button className={$state.isDisableFlag1 ? '' : 'button-in-step'} disabled={$state.isDisableFlag1} onClick={this.handleAddRow}>新增</Button>
            <Table
              className="plain-gray-table"
              dataSource={$state.topThreeDTO}
              columns={this.columns}
              pagination={false}
              bordered
              rowKey={record => record.orderNum}
            />
          </div>
        )
      }
    }
    
    export default Form.create(
      {
        onValuesChange(props, changeValues, allValues) { }
        
      }
    )(ThirdTable)
    
    • mock.json 模拟的数据
    {
      "code": 200,
      "modelList": [
        {
          "orderNum": "1",
          "projectName": { "name": "绿州", "num": "100" },
          "averagePrice": "10000"
        },
        {
          "orderNum": "2",
          "projectName": { "name": "长岛", "num": "101" },
          "averagePrice": "13000"
        },
        {
          "orderNum": "3",
          "projectName": { "name": "紫荆", "num": "102" },
          "averagePrice": "17000"
        }  
      ]
    }
    
    
    • state.js 数据操作
    import { observable, action, toJS } from 'mobx'
    import $mock from './mock.json'
    
    class State {
      @observable topThreeDTO = []//均价前三名
      @observable isDisableFlag1 = true//表格新增按钮是否禁用
    
      @action queryDetails = async () => {
        const res = await $mock
        console.log(res);
    
        if (res.code == 200) {
          this.topThreeDTO = res.modelList
        }}
    }
    export default new State();
    
    • index.less
    .ant-select.ant-select-enabled {
      width:100%;
    }
    .table-title {
      color:red;
    }
    .plain-gray-table.ant-table-wrapper {
    		margin-top: 20px;
    		thead > tr > th {
    			background: #cde6ff;
    			// color: #0D152A;
    			font-weight: 700;
    			text-align: left;
    			padding: 12px 16px;
    		}
    		thead > tr:first-child > th:first-child {
    			border-top-left-radius: 0;
    		}
    		thead > tr:first-child > th:last-child {
    			border-top-right-radius: 0;
    		}
    		tbody > tr:nth-child(odd) {
    			background: #fff;
    		}
    		tbody > tr:nth-child(even) {
    			background: #f6f7fa;
    		}
    		tbody > tr > td {
    			text-align: center;
    			padding: 7px 16px;
    			color: #0d152a;
    			button {
    				color: #5c8ae5;
    				background: #d9ecff;
    				border-radius: 10px;
    				border: none;
    				padding: 0 12px;
    			}
    		}
    		.ant-table-tbody > tr.ant-table-row-hover:not(.ant-table-expanded-row) > td,
    		.ant-table-tbody > tr:hover:not(.ant-table-expanded-row) > td {
    			background: #e1e6ef;
    		}
    	}
    
    展开全文
  • 最近项目中h5端要实现图文上传,而且还要支持用户用户输入的格式,例如换行啥的,那么使用输入控件保存输入内容,图片上传控件就不合适了,因为很难知道用户...首先,div默认是不可编辑的,需要设置它可以编辑,这个...

    最近项目中h5端要实现图文上传,而且还要支持用户用户输入的格式,例如换行啥的,那么使用输入控件保存输入内容,图片上传控件就不合适了,因为很难知道用户的输入样式。

    如果使用一些现有的富文本编辑器,貌似又不是很划算,所以综合考虑使用div来自己实现一个就是比较理想的方案了。

    先来考虑一下,如果使用div来实现简单的富文本编辑器,需要解决哪些问题?

    首先,div默认是不可编辑的,需要设置它可以编辑,这个很简单只需要使用

       contentEditable="true"
    

    其次,我们需要在div指定的位置插入图片,指定位置就是光标所在的位置,那么我们插入图片的时候,需要知道光标的位置,网上查了下应该是需要getSelection API W3Cschool上面直接有简单的用法,感兴趣的童鞋可以去看看。

    获取当前光标选中位置

    let selection = window.getSelection();
    let range = selection.getRangeAt(0);
    

    那么知道了光标位置,怎么插入图片?

     let img = document.createElement("img");
       img.src = json.url;
       //最大宽度为手机宽度减去20
       img.style.maxWidth = (width-20) + 'px';
       range.insertNode(img);//选中位置插入图片   
    

    这就完了?

    当然还没完,实现中遇到了另一个问题,那就是焦点的变化。如果我想插入图片,我就首先需要上传图片,但是当我点击上传图片的按钮的时候,焦点就已经发生了变化,这个时候获取的选中位置就是你点击的位置!

    那么该如何解决这个问题呢?

    仔细分析,点击的时候,焦点变化的时候,我们需要记录下上次焦点的位置,上次焦点的位置在哪里?在可编辑的div中,焦点变化的时候,就是可编辑div失去焦点的时候!

    那么是否可以监听div失焦这个事件呢?答案当然是的!

     onBlur={() => {
       let selection = window.getSelection();
       range = selection.getRangeAt(0);
       }}
    

    给div实现onBlur监听就可以了,是不是很简单?

    接下来看一下完整的代码

    import React, {Component} from "react";
    import "../../assets/css/topic/DivEdit.css";
    import "../../assets/common/second-common.css";
    ​
    let range;
    let width = document.documentElement.clientWidth;
    //头部栏
    class DivEdit extends Component {
        constructor(props) {
            super(props);
            let typeArr = [".png", ".jpg", ".jpeg", ".bmp", ".gif"];
            this.state = {
                id:'',
                inputValueHtml: '',
                fileType: typeArr,
                showTips:true
            }
        }
    ​
    ​
        //光标定位在可编辑div的开始的位置
        setStartFocus() {
    ​
            document.querySelector('#my-question-define-edit').focus();
    ​
        }
    ​
    ​
        //光标定位在内容的尾端
        setEndFocus() {
    ​
    ​
            let srcObj = document.querySelector('#my-question-define-edit');
            let selection = window.getSelection();
            range = document.createRange();
            range.selectNodeContents(srcObj);
            selection.removeAllRanges();
            selection.addRange(range);
            range.setStart(srcObj, 1);
            range.setEnd(srcObj, 1);
    ​
        }
    ​
    ​
        // 调用input 选择文件
        triggerSelect() {
            return document.getElementById('topic-add-img').click();
        }
    ​
    ​
        //处理上传文件
        handleChange(file) {
            // 判断文件类型进行上传
            if (window.typeMatch(this.state.fileType, file.name)) {
                // 上传文件
                this.saveFile(file);
            } else {
                Toast.fail("文件类型不符,请重新选择", 3);
            }
        }
    ​
        // 上传文件
        saveFile(file) {
         
         //你们自己处理上传的处理 //当成功的时候
        
                 let img = document.createElement("img");
                 img.src = json.url;
                 img.style.maxWidth = (width-20) + 'px';
    ​
                if(range) {
    ​
                      range.insertNode(img);
    ​
               }else{
    ​
                    this.setStartFocus();
                    let selection = window.getSelection();
                    range = selection.getRangeAt(0);
                    range.insertNode(img);
    ​
                  }
       
        }
    ​
        componentDidMount() {
            let question=this.props.question;
            this.setState({
            inputValueHtml: '<p>' + question + '</p><br/><br/><br/>',showTips:!(question&&question!=='')
            }, 
            () => {
    ​
                if(question&&question!==''){
    ​
                    this.setEndFocus();
    ​
                }
            });
    ​
        }
    ​
    ​
        getHtml(){
    ​
            return this._editDiv.innerHTML;
    ​
        }
    ​
    ​
        render() {
    ​
    ​
            return (
    ​
                <div className={'add-my-question-first-edit'} >
    ​
                    <div id={'my-question-define-edit'}
                         onFocus={() => {
    ​
                             this.setState({showTips:false});
    ​
                         }}
                         onBlur={() => {
                             let selection = window.getSelection();
                             range = selection.getRangeAt(0);
                         }}
                         onClick={() => {
    ​
                             let selection = window.getSelection();
                             range = selection.getRangeAt(0);
    ​
                         }}
                         ref={(editDiv) => this._editDiv = editDiv}
                         className={'add-my-question-edit'}
                         contentEditable="true"
                         dangerouslySetInnerHTML={{__html: this.state.inputValueHtml}}/>
    ​
                    {
    ​
                        this.state.showTips?
                            <span style={{
                            position: 'absolute',
                            top:10,
                            left:10,
                            marginTop:'1.333rem',
                            fontSize:17,color:'#E8E8E8'
                            }}>输入您的问题...</span>:null
    ​
                    }
    ​
                    <div className={'add-bottom-menu'}>
    ​
                        <img style={{width: 20, position: 'absolute', left: 10}}
                             src={require("../../assets/images/topic_topic_show.png")}
                             alt='箭头'/>
    ​
    ​
                        <div className={'topic-add-pic'}
                             onClick={() => {
                                  //调起上传图片
                                 this.triggerSelect();
                                 
                             }}>
                            <img style={{width: 20}}
                                 src={require("../../assets/images/topic_upload_pic.png")}
                                 alt='上传图片'/>
    ​
                            <span style={{marginLeft: 10, fontSize: 15}}>上传图片</span>
                        </div>
    ​
    ​
                    </div>
                    
                    <div style={{visibility: 'hidden'}}>
                        <input
                            type="file"
                            id={'topic-add-img'}
                            style={{display: "none"}}
                            onChange={e => this.handleChange(e.target.files[0])}
                        />
                    </div>
    ​
                </div>
    ​
            );
        }
    }
    ​
    export default DivEdit;​
    

    样式表

    .add-my-question-first-edit {
        display: flex;
        flex-direction: column;
        flex: 1;
    ​
     }
    ​
    .add-my-question-first-edit  .add-my-question-edit{
    ​
        flex: 1;
        margin-top: 1.333rem;
        /*margin-bottom: 1.333rem;*/
        font-size: 0.453rem;
        background-color: #fff;
        padding: 10px 10px 1.867rem;
    ​
    }
    ​
    .add-my-question-first-edit  .add-bottom-menu{
    ​
        position: fixed;
        bottom: 0;
        width: 100%;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        height: 1.067rem;
        background-color: #fff;
        border-top: #E8E8E8 solid 1px;
    ​
    ​
    ​
    }
    ​
    .add-my-question-first-edit  .add-bottom-menu .topic-add-pic{
    ​
        display: flex;
        flex-direction: row;
        align-items: center;
        align-self: center;
    ​
    }
    

    更多内容,欢迎同步关注作者公众号二维码!
    程序员内功修炼手册 主要发布计算机基础、设计模式、计算机网络基础知识,同时重点关注大前端知识
    Android、iOS、web前端、Flutter、React Native等,想学习大前端知识的速度来吧,一起学习、一起成长!
    qrcode_for_gh_f730c342ff6e_344.jpg

    展开全文
  • div绑定键盘事件

    2020-03-31 18:58:20
    在某一次给 GridManager 中的div元素绑定键盘事件(如keydown)时, 发现绑定是无效。 排除一些问题点后,最终找到了解决方法。 解决方法: 给当前元素增加 tabindex 属性 <div tabindex="-1"></div> 原理...
  • react中使用富文本编辑react+wangEditor前言第一步第二步第三步第四步第五步完整代码写在最后 前言 近日在使用react写项目的过程中需要使用到富文本编辑器,之前使用的一直是百度富文本框,这次想换一个,于是...
  • React开发过程中,有时需要使用原生的...比如存在数据库中的,可编辑的HTML 实现代码如下: const htmlString= '<p>Hello World</p>' render () { return ( <div className='editor-wrapper' dan...
  • 这只一个雏形,但是可以用了。...import {Component} from 'react' const Action = props =&gt; { console.log(props) return ( &lt;div&gt; &lt;button type='button' onClick={pr...
  • 一个可编辑div,如果我点击了div外的一个按钮,该怎么让div中光标不消失并停在原来的位置上?直接在点击事件中触发div.focus()为什么会使光标出现在div的开头?
  • 注意点:1、事件名称由react提供,所以事件名首字母大写。比如onClick,onMouseOver。 2、为事件提供的处理函数,格式必须是onClick={function},没有小括号。 3、绑定事件的格式写法为: <button onClick={()...
  • /* * @Description: * @Author: wanghuilan885 * @Date: 2019-07-09 17:37:24 * @LastEditTime: 2019-12-05 10:59:22 * @LastEditors: Please set LastEditors ...import React from 'react' import { Icon,...
  • 我在用react想写一个可以编辑的表格,我把ant design上的可编辑表格的代码复制到我的项目中,而且把react的版本升级到了16.3.0,但是在运行项目时出现了下面的报错!![图片说明]...
  • React-事件处理详解

    2018-08-06 17:05:03
    React通过将事件处理器 绑定到组建上处理事件事件触发的同时更新组建的内部状态,内部状态更新会触发组件的重绘。因此,如果视图层想要渲染出事件出发后的结果,它所要做的就是渲染函数中读取组件的内部状态。 ...
  • 最近因为工作需要,要基于react-ant做一个可编辑表格,具体功能如图所示,可新增,删除,批量删除,保存等功能,
  • 1. 给div增加contenteditable="true",是div变成可编辑状态 2.给div增加tabindex="0"tabindex的值是多少都可以,只要有这个属性存在,tabindex的实际作用是用户按tab键时焦点顺序切换的索引设置,结果居然可以解决...
  • 你听过 React Fragments吗 ? React 中常见模式是为一个组件返回多个元素。为了包裹多个元素你肯定写过很多的 div 和 span,进行不必要的嵌套,无形中增加了浏览器的渲染压力。 版本15 15以前,render 函数的返回...
  • 在做编辑页面的时候遇到一个需求是“在指定状态下内容不可编辑” 方案一:给每个<Input>、<Select>...添加disable属性 这种方案在form表单内容比较多的情况下可能不是很方便,所以辜老师帮我想了方案...
  • 基于React+AntDesign实现的一个自定义的可编辑表格,主要用于数据库表字段的编辑、带翻译功能,稍作修改后也可复用到其他地方。 主要包括三个文件:index.js,EditableTable.js,EditableTable.less,其中图标是使用的...
  • 技术栈为纯React。接下来介绍一些稍微重要的技术点: contentEditable 核心的编辑功能用到了HTML5的 contentEditable 属性,但是在 react 中,你不能直接写下面的这种组件 &lt;div contentEditable&gt; ...
1 2 3 4 5 ... 20
收藏数 3,576
精华内容 1,430
关键字:

div可编辑事件 react