Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用MaterialUI创建代码编辑器,如自动完成下拉列表?_Javascript_Reactjs_Material Ui - Fatal编程技术网

Javascript 如何使用MaterialUI创建代码编辑器,如自动完成下拉列表?

Javascript 如何使用MaterialUI创建代码编辑器,如自动完成下拉列表?,javascript,reactjs,material-ui,Javascript,Reactjs,Material Ui,我有一个非常具体的用例,我正在考虑如何在我正在开发的应用程序中实现。 该组件是类似于编辑器的文本区域,应该填充材质UI芯片组件(类似于自动完成文本框中的标记),这些组件生成某种表达式。当用户开始在此文本区域内键入时,将弹出一个自动完成下拉列表,向用户显示可能的选项 我希望将此下拉列表放置在IDE中的此文本区域内(类似于intellisense)。 我正试图通过使用Autocomplete和某种自定义Popper组件的组合来实现这个组件。 代码如下所示(仍处于某种起草阶段): 从'@materia

我有一个非常具体的用例,我正在考虑如何在我正在开发的应用程序中实现。 该组件是类似于编辑器的文本区域,应该填充材质UI芯片组件(类似于自动完成文本框中的标记),这些组件生成某种表达式。当用户开始在此文本区域内键入时,将弹出一个自动完成下拉列表,向用户显示可能的选项

我希望将此下拉列表放置在IDE中的此文本区域内(类似于intellisense)。

我正试图通过使用Autocomplete和某种自定义Popper组件的组合来实现这个组件。 代码如下所示(仍处于某种起草阶段):

从'@material ui/core/styles'导入{createStyles,makeStyles,Theme};
从“@material ui/core/TextField”导入TextField;
从“@material ui/lab/Autocomplete”导入自动完成;
从“@material ui/core/Chip”导入芯片;
从“@material ui/core”导入{Popper}”;
常量目标选项=[
{label:(”,类型:“operator”},
{label:”,键入:“operator”},
{label:“OR”,键入:“operator”},
{label:“AND”,键入:“operator”},
{标签:“测试选项1”,类型:“选项”},
{标签:“测试选项2”,类型:“选项”},
];
const useStyles=makeStyles((主题:主题)=>
创建样式({
根目录:{
“&.muiautomlete inputRoot”:{
对齐项目:“开始”
}
},
}),
);
导出默认值()=>{
const classes=useStyles();
const[value,setValue]=React.useState([]);
const CustomPopper=函数(道具){
返回;
};
返回(
选项(标签)}
自由女神
不可清除
PopperComponent={CustomPopper}
renderTags={(值:string[],getTagProps)=>
value.map((选项:字符串,索引:编号)=>(
))
}
renderInput={(参数)=>(
)}
/>
);
};
const useStyles=makeStyles((主题:主题)=>
创建样式({
根目录:{
“&.muiautomlete inputRoot”:{
对齐项目:“开始”
}
},
}),
);
导出默认值()=>{
const classes=useStyles();
const CustomPopper=函数(道具){
返回;
};
返回(
选项(标签)}
自由女神
不可清除
PopperComponent={CustomPopper}
renderTags={(值:string[],getTagProps)=>
value.map((选项:字符串,索引:编号)=>(
))
}
renderInput={(参数)=>(
)}
/>
);
};
  • 如何将此下拉式(Popper)波纹管文本光标定位在文本区域内
  • 该组件还应该能够格式化创建的表达式(同样类似于代码编辑器格式化程序)。您认为这是该用例的正确方法,还是应该使用其他库和/或UI组件

  • 谢谢。

    警告:这将深入到意见的领域。。。我最终选择了降档进行定制
    npm安装降档

    这段代码有点脏(出自我的开发分支),但它有一个定制的下拉列表,您可以编辑它

        import React from 'react'
    import {render} from 'react-dom'
    import Downshift from 'downshift'
    
    import {
      MenuItem,
      Paper,
      TextField,
    } from '@material-ui/core'
    
    import {
      withStyles
    } from '@material-ui/core/styles'
    
    const items = [
      'apple',
      'pear',
      'orange',
      'grape',
      'banana',
    ]
    
    class DownshiftWrapper extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          value: props.value || '',
          backup: props.value || '',
          onChange: v => {console.log('changed', v)}
        }
      }
    
      _renderMenuItem(args) {
        const { key, index, itemProps, current, highlightedIndex, selectedItem, ...rest } = args
        const isSelected = key == current
        return (
          <MenuItem
            {...rest}
            key = { key }
            selected = { isSelected }
            component='div'
            style={{
              fontWeight: isSelected ? 500 : 400,
              padding: '2px 16px 2px 16px',
              borderBottom: '1px solid rgba(128,128,128,0.5)',
            }}
          >
            { key }
          </MenuItem>
        )
      }
      render() {
        const { classes, style } = this.props
    
        const _override = (incoming) => {
          console.log('override:', incoming)
          this.setState({
            ...this.state,
            value: incoming
          })
    
          if(this.props.onChange) {
            this.props.onChange(incoming)
          } else {
            console.log(`Downshift::onChange the onchange handler is missing. New value:${incoming}`)
          }      
        }
    
        return (
          <Downshift
            ref = { x => this.downshift = x}
            onSelect = { (selected) => {
              if(selected) {
                console.log('::onSelect', selected) 
                _override(selected)
              }
            } }
            onInputValueChange= { (inputValue, stateAndHelpers) => {
              console.log('::onInputValueChange', {
                ...stateAndHelpers,
                _val: inputValue,
              })
            } }
            // onStateChange={( state ) => {
            //   //return input.onChange(inputValue);
            //   let value = state.inputValue
    
            //   this.state.onChange(state.inputValue)
            //   console.log('old:state', state)
            //   console.log('value:', value)
    
            //   _override( state.inputValue )
            // }}
            onChange={ selection => { console.log(selection) }}
            itemToString={ item => {
              return item || ''
            } }
            //selectedItem={this.props.input.value}
          >
          {({
            getInputProps,
            getItemProps,
            getLabelProps,
            getMenuProps,
            isOpen,
            inputValue,
            highlightedIndex,
            selectedItem,
          }) => {
            const inputProps = getInputProps()
            let value = inputProps.value
    
            //FIXME add filtering options
            let filtered = this.props.items || items//.filter(item => !inputValue || item.includes(inputValue))
    
            return (
              <div className={classes.container}>
                <TextField 
                  { ...inputProps } 
                  style={
                    style
                  }
                  label={this.props.label}
                  placeholder={this.props.placeholder}
                  
                  value = { 
                    this.state.value 
                  }
                  onFocus = { e => {
                    this.downshift.openMenu()
                    e.target.select()
                  }}
                  onBlur={ e => { 
                    console.log(inputValue) 
                    e.preventDefault()
                    this.downshift.closeMenu()
                  } }  
                  onChange={ e => {
                    inputProps.onChange(e)//pass to the logic
                    _override(e.target.value)
                  }}
                  onKeyDown= { (e) => {
                    const key = e.which || e.keyCode
                    if(key == 27){
                      e.preventDefault()
                      e.target.blur()
                       //reset to default
                      _override(this.state.backup || '')
                    } else if (key == 13){
                      e.preventDefault()
                      e.target.blur()
                      _override(e.target.value)
                    }
                  }}
                />
                {isOpen
                  ? (
                    <Paper 
                      className={classes.paper}
                      // style={{
                      //   backgroundColor: 'white',
                      // }}
                    square>
                      { filtered
                          .map( (item, index) => {
                            const _props = {
                              ...getItemProps({ item: item }),
                              index: index,
                              key: item,
                              item: item,
                              current: this.state.value,
                            } 
                            return this._renderMenuItem(_props)  
                          } )
                      }
                    </Paper>
                  )
                  : null}
    
                {/* <div style={{color: 'red'}}>{this.state.value || 'null'}</div> */}
              </div>
            )
            
          } }
          </Downshift>
        )
      }
    }
    
    class Integrated extends React.Component {
    
    }
    
    //Material UI Examples -> https://material-ui.com/demos/autocomplete/
    const styles = theme => ({
      root: {
        flexGrow: 1,
        height: 250,
      },
      container: {
        flexGrow: 1,
        position: 'relative',
      },
      paper: {
        position: 'absolute',
        zIndex: 1,
        marginTop: theme.spacing.unit,
        left: 0,
        right: 0,
      },
      chip: {
        margin: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 4}px`,
      },
      inputRoot: {
        flexWrap: 'wrap',
      },
    })
    
    export default withStyles(styles)(DownshiftWrapper)
    

    谢谢你的麻烦,我想我也会放弃自动完成并手动创建组件。基本上,这是一个非传统的商业需求,不是我自己发明的东西,我只是想澄清我对此的疑虑,看看过去是否有人有类似的问题。我还需要支持Textfield内芯片的布局调整,我认为Material UI组件不可能做到这一点。
        import React from 'react'
    import {render} from 'react-dom'
    import Downshift from 'downshift'
    
    import {
      MenuItem,
      Paper,
      TextField,
    } from '@material-ui/core'
    
    import {
      withStyles
    } from '@material-ui/core/styles'
    
    const items = [
      'apple',
      'pear',
      'orange',
      'grape',
      'banana',
    ]
    
    class DownshiftWrapper extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          value: props.value || '',
          backup: props.value || '',
          onChange: v => {console.log('changed', v)}
        }
      }
    
      _renderMenuItem(args) {
        const { key, index, itemProps, current, highlightedIndex, selectedItem, ...rest } = args
        const isSelected = key == current
        return (
          <MenuItem
            {...rest}
            key = { key }
            selected = { isSelected }
            component='div'
            style={{
              fontWeight: isSelected ? 500 : 400,
              padding: '2px 16px 2px 16px',
              borderBottom: '1px solid rgba(128,128,128,0.5)',
            }}
          >
            { key }
          </MenuItem>
        )
      }
      render() {
        const { classes, style } = this.props
    
        const _override = (incoming) => {
          console.log('override:', incoming)
          this.setState({
            ...this.state,
            value: incoming
          })
    
          if(this.props.onChange) {
            this.props.onChange(incoming)
          } else {
            console.log(`Downshift::onChange the onchange handler is missing. New value:${incoming}`)
          }      
        }
    
        return (
          <Downshift
            ref = { x => this.downshift = x}
            onSelect = { (selected) => {
              if(selected) {
                console.log('::onSelect', selected) 
                _override(selected)
              }
            } }
            onInputValueChange= { (inputValue, stateAndHelpers) => {
              console.log('::onInputValueChange', {
                ...stateAndHelpers,
                _val: inputValue,
              })
            } }
            // onStateChange={( state ) => {
            //   //return input.onChange(inputValue);
            //   let value = state.inputValue
    
            //   this.state.onChange(state.inputValue)
            //   console.log('old:state', state)
            //   console.log('value:', value)
    
            //   _override( state.inputValue )
            // }}
            onChange={ selection => { console.log(selection) }}
            itemToString={ item => {
              return item || ''
            } }
            //selectedItem={this.props.input.value}
          >
          {({
            getInputProps,
            getItemProps,
            getLabelProps,
            getMenuProps,
            isOpen,
            inputValue,
            highlightedIndex,
            selectedItem,
          }) => {
            const inputProps = getInputProps()
            let value = inputProps.value
    
            //FIXME add filtering options
            let filtered = this.props.items || items//.filter(item => !inputValue || item.includes(inputValue))
    
            return (
              <div className={classes.container}>
                <TextField 
                  { ...inputProps } 
                  style={
                    style
                  }
                  label={this.props.label}
                  placeholder={this.props.placeholder}
                  
                  value = { 
                    this.state.value 
                  }
                  onFocus = { e => {
                    this.downshift.openMenu()
                    e.target.select()
                  }}
                  onBlur={ e => { 
                    console.log(inputValue) 
                    e.preventDefault()
                    this.downshift.closeMenu()
                  } }  
                  onChange={ e => {
                    inputProps.onChange(e)//pass to the logic
                    _override(e.target.value)
                  }}
                  onKeyDown= { (e) => {
                    const key = e.which || e.keyCode
                    if(key == 27){
                      e.preventDefault()
                      e.target.blur()
                       //reset to default
                      _override(this.state.backup || '')
                    } else if (key == 13){
                      e.preventDefault()
                      e.target.blur()
                      _override(e.target.value)
                    }
                  }}
                />
                {isOpen
                  ? (
                    <Paper 
                      className={classes.paper}
                      // style={{
                      //   backgroundColor: 'white',
                      // }}
                    square>
                      { filtered
                          .map( (item, index) => {
                            const _props = {
                              ...getItemProps({ item: item }),
                              index: index,
                              key: item,
                              item: item,
                              current: this.state.value,
                            } 
                            return this._renderMenuItem(_props)  
                          } )
                      }
                    </Paper>
                  )
                  : null}
    
                {/* <div style={{color: 'red'}}>{this.state.value || 'null'}</div> */}
              </div>
            )
            
          } }
          </Downshift>
        )
      }
    }
    
    class Integrated extends React.Component {
    
    }
    
    //Material UI Examples -> https://material-ui.com/demos/autocomplete/
    const styles = theme => ({
      root: {
        flexGrow: 1,
        height: 250,
      },
      container: {
        flexGrow: 1,
        position: 'relative',
      },
      paper: {
        position: 'absolute',
        zIndex: 1,
        marginTop: theme.spacing.unit,
        left: 0,
        right: 0,
      },
      chip: {
        margin: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 4}px`,
      },
      inputRoot: {
        flexWrap: 'wrap',
      },
    })
    
    export default withStyles(styles)(DownshiftWrapper)
    
    return (
            <EditableSelect 
              //onFocus={e => this.onFocus(e) }
              //multiLine={true}
              //onKeyDown={ e=> this.keyHandler(e) }
              items={ options }
              value={ cue.spots[index][field] }
              hintText={T.get('spot' + field + 'Hint')}
              placeholder={ T.get('spot' + field + 'Hint') }
              ref={x => this[id] = x }
              style={{width: '90%' }}
              onChange={ val => this.updateSpotExplicit(val, index, field) } 
            />
          )
    
    "@material-ui/core": "^4.11.2",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.57",
    "@material-ui/styles": "^4.11.2",
    "downshift": "^2.0.10",