【问题标题】:SPFX web part to add Text and show it inside a Popup when clicking on a buttonSPFX Web 部件添加文本并在单击按钮时在弹出窗口中显示它
【发布时间】:2023-03-10 07:28:01
【问题描述】:

我正在尝试使用 SPFX Web 部件来实现这一点:-

  • Web 部件将呈现一个 Button 并在其设置中包含一个文本字段。

  • 用户添加 Web 部件 >> 编辑它 >> 在文本字段内(设置页面内)输入文本 >> 保存 Web 部件 >> 然后 Web 部件将呈现一个按钮 >> 如果用户单击在按钮上将显示一个弹出窗口,其中包含输入的文本。

现在我找到了这个链接@https://www.c-sharpcorner.com/article/conecpt-of-react-portal-in-spfx/,它几乎可以实现我想要的,除了示例中的弹出文本是在.tsx 文件中硬编码的。那么制作的步骤是什么弹出文本可在 Web 部件设置中配置,而不是硬编码?

谢谢

这是我的ReactPortalWebPart.ts 文件:-

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';

import * as strings from 'ReactPortalWebPartStrings';
import ReactPortal from './components/ReactPortal';
import { IReactPortalProps } from './components/IReactPortalProps';

export interface IReactPortalWebPartProps {
  description: string;
}

export default class ReactPortalWebPart extends BaseClientSideWebPart<IReactPortalWebPartProps> {

  public render(): void {
    const element: React.ReactElement<IReactPortalProps> = React.createElement(
      ReactPortal,
      {
        description: this.properties.description
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected onDispose(): void {
    ReactDom.unmountComponentAtNode(this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('description', {
                  label: strings.DescriptionFieldLabel
                })
              ]
            }
          ]
        }
      ]
    };
  }
}

这里是ReactPortal.tsx:-

import * as React from 'react';  
    import { IReactPortalProps } from './IReactPortalProps';  
    import Myportal from "./Myportal";  
    export default class ReactPortal extends React.Component<IReactPortalProps, {}> {  
      public render(): React.ReactElement<IReactPortalProps> {  
        return (  
          <div >  
          <Myportal/>  
          </div>  
        );  
      }  
    }  

这里是Myportal.tsx:-

    import* as React from "react";  
    import usePortal from "react-cool-portal";  
    import "./mystyle.scss";  
    const  Myportal = () => {  
     // const { Portal } = usePortal({ containerId: "my-portal-root" });  
      const { Portal, show, hide } = usePortal({ defaultShow: false,containerId:"my-portal-root" });  
      const handleClickBackdrop = (e: React.MouseEvent) => {  
        const { id } = e.target as HTMLDivElement;  
        if (id === "modal") hide();  
      };  
      
      return (  
            <div className="App">  
         
          <button className="btn" onClick={show} type="button">  
            Who we are 
          </button>  
         &nbsp; &nbsp; &nbsp;
          <button className="btn" onClick={show} type="button">  
            Our value 
          </button> 
          <Portal>  
            <div  
              id="modal"  
              className="modal"  
              onClick={handleClickBackdrop}  
              tabIndex={-1}  
            >  
              <div  
                className="modal-dialog"  
                role="dialog"  
                aria-labelledby="modal-label"  
                aria-modal="true"  
              >  
                <div className="modal-header">  
                
                  <button  
                    className="modal-close"  
                    onClick={hide}  
                    type="button"  
                    aria-label="Close"  
                  >  
                    <span aria-hidden="true">×</span>  
                  </button>  
                </div>  
                <div className="modal-body">  
                 <h1> Who we are</h1>
<h3>.................................................</h3>
Our overriding purpose is to dramatically improve the reliability, efficiency........
                </div>  
              </div>  
            </div>  
          </Portal>  
        </div>  
          
      );  
    };  
    export default Myportal;  

【问题讨论】:

  • 这里不清楚你的意思。如果您希望对话框访问存储在 Web 部件属性中的文本,为什么不将它从您的 Web 部件传递给您的对话框??
  • @Nikolay 是的,我想在 Web 部件设置中添加所需的 HTML ...然后当 Web 部件呈现按钮并且用户单击按钮以显示 HTML ...我知道我的要求听起来很简单..但我不确定我该怎么做?谢谢
  • @Nikolay 你能检查我的编辑吗.. 我提供了我的 SPFX 的代码.. 谢谢
  • 嗯,你为什么要使用传送门?!您不能在没有任何门户的情况下简单地呈现您的 Web 部件吗?我的意思是,将“描述”传递给要呈现它的组件(这里称为“MyPortal”并且没有任何属性。您需要将描述传递给该组件)。也许这会有所帮助:React 中的组件和属性是什么:reactjs.org/docs/components-and-props.html
  • @Nikolay 我正在关注此链接@c-sharpcorner.com/article/conecpt-of-react-portal-in-spfx 以显示弹出窗口.. 谢谢.. 你能就此提供更多建议吗?

标签: javascript reactjs sharepoint spfx


【解决方案1】:

我认为您需要将 MyPortal 重写为 React 组件;下面我尝试写了一些关于MyPortal.tsxReactPortal.tsx 所需更改的示例,但我当时没有进行测试。

ReactPortal.tsx:

import * as React from 'react';  
    import { IReactPortalProps } from './IReactPortalProps';
    import { IMyportalProps } from './IMyportalProps'; 
    import Myportal from "./Myportal";  
    export default class ReactPortal extends React.Component<IReactPortalProps, {}> {  
      public render(): React.ReactElement<IReactPortalProps, IMyportalProps> {  
        return (  
          <div >  
          <Myportal title="Who we are" body="Our overriding purpose is to dramatically improve the reliability, efficiency........"/>  
          </div>  
        );  
      }  
    }

MyPortal.tsx

    import* as React from "react";  
    import usePortal from "react-cool-portal";  
    import "./mystyle.scss";
    export interface IMyportalProps {
       title: string;
       body: string
    }
    class Myportal extends React.Component  
<IMyportalProps> {    
       constructor(props: IUnderstandStateComponentProps) {    
       super(props);
    }
    public render(): React.ReactElement  
    <IMyportalProps> {  
      const { Portal, show, hide } = usePortal({ defaultShow: false,containerId:"my-portal-root" });  
      const handleClickBackdrop = (e: React.MouseEvent) => {  
        const { id } = e.target as HTMLDivElement;  
        if (id === "modal") hide();  
      };  
      
      return (  
            <div className="App">  
         
          <button className="btn" onClick={show} type="button">  
            Who we are 
          </button>  
         &nbsp; &nbsp; &nbsp;
          <button className="btn" onClick={show} type="button">  
            Our value 
          </button> 
          <Portal>  
            <div  
              id="modal"  
              className="modal"  
              onClick={handleClickBackdrop}  
              tabIndex={-1}  
            >  
              <div  
                className="modal-dialog"  
                role="dialog"  
                aria-labelledby="modal-label"  
                aria-modal="true"  
              >  
                <div className="modal-header">  
                
                  <button  
                    className="modal-close"  
                    onClick={hide}  
                    type="button"  
                    aria-label="Close"  
                  >  
                    <span aria-hidden="true">×</span>  
                  </button>  
                </div>  
                <div className="modal-body">  
                 <h1>{this.props.title}</h1>
<h3>.................................................</h3>
{this.props.body}
                </div>  
              </div>  
            </div>  
          </Portal>  
        </div>  
          
      );  
    };

【讨论】:

  • 我认为将其重写为“反应组件”并不是真正需要的,您可以声称它已经是反应“功能组件”。您需要做的就是将属性传递给它(作为参数)。但是你也可以将它重写为一个类,是的。
【解决方案2】:

我的尝试:) 这个想法是,您将“描述”从 Web 部件传递到对话框。 请阅读the link above,如何将 React 中的属性从父组件传递给子组件(或一些基本的 React 教程),如果您选择使用 React 使用 SPFx,强烈建议您阅读。

请注意,在 SPFx 中创建对话框的更简单方法可能是使用 Microsoft Fluent UI 库,它适用于 SPFx,有许多教程,支持 SharePoint 主题等。特别是,它具有“@ 987654323@" 内置组件,以及许多其他有用的组件和控件。

无论如何,我们在这里使用“react-cool-portal”。查看下面代码中的 cmets。

ReactPortal.tsx

import * as React from 'react';  
    import { IReactPortalProps } from './IReactPortalProps';  
    import Myportal from "./Myportal";  
    export default class ReactPortal extends React.Component<IReactPortalProps, {}> {

      // pass further the parameter that was received from the web part.
      // The "description was passed to "ReactPortal" from WebPart with:
      // React.createElement(
      //   ReactPortal,
      //   {
      //     description: this.properties.description
      //   }

      public render(): React.ReactElement<IReactPortalProps> {  
        return (  
          <div>  
          <!-- pass the parameter down to the child component -->
          <Myportal description={this.props.description} />  
          </div>  
        );  
      }  
    }  

Myportal.tsx

    import* as React from "react";  
    import usePortal from "react-cool-portal";  
    import "./mystyle.scss";  

    // accept properties (added "props" argument)
    // and use it below in HTML {props.description}

    const  Myportal = (props) => {  
     // const { Portal } = usePortal({ containerId: "my-portal-root" });  
      const { Portal, show, hide } = usePortal({ defaultShow: false,containerId:"my-portal-root" });  
      const handleClickBackdrop = (e: React.MouseEvent) => {  
        const { id } = e.target as HTMLDivElement;  
        if (id === "modal") hide();  
      };  
      
      return (  
            <div className="App">  
         
          <button className="btn" onClick={show} type="button">  
            Who we are 
          </button>  
         &nbsp; &nbsp; &nbsp;
          <button className="btn" onClick={show} type="button">  
            Our value 
          </button> 
          <Portal>  
            <div  
              id="modal"  
              className="modal"  
              onClick={handleClickBackdrop}  
              tabIndex={-1}  
            >  
              <div  
                className="modal-dialog"  
                role="dialog"  
                aria-labelledby="modal-label"  
                aria-modal="true"  
              >  
                <div className="modal-header">  
                
                  <button  
                    className="modal-close"  
                    onClick={hide}  
                    type="button"  
                    aria-label="Close"  
                  >  
                    <span aria-hidden="true">×</span>  
                  </button>  
                </div>  
                <div className="modal-body">  
                 <h1> Who we are</h1>
<!-- use the property value somehow -->
<h3>{props.description}</h3>
                </div>  
              </div>  
            </div>  
          </Portal>  
        </div>  
          
      );  
    };  
    export default Myportal;  

【讨论】:

    【解决方案3】:

    您可以通过两种方式实现这一目标。

    1. 将弹出内容存储为页面属性的一部分,一旦您编辑页面,该属性就会保留
    2. 将弹出内容存储在列表中,并在呈现页面时获取数据。仅供参考,还没有完全考虑如何通过这种方式实现它。

    我已经更新了您提供的代码的相关部分,以展示如何通过将弹出内容存储为页面属性的一部分来实现预期。

    在 props 中添加了另一个属性来存储弹出内容

    export interface IReactPortalWebPartProps {
    description: string;
    content?: string;
    }
    

    更新了组件ReactPortalWebPart.ts的render方法

        public render(): void {
          const element: React.ReactElement<any> = React.createElement(
            ReactPortal,
            {
              mode: this.displayMode, //used to determine if to display the text input or not based on the current state of the webpart.
              content: this.properties.content, //the contents property of the webpart which is persisted in the page properties.
              description: this.properties.description,
              updateWebPartContent: this.updateWebPartContentProperty.bind(this) // the function that would be called from the portal component when the content is saved by the user
            }
          );
    
        private updateWebPartContentProperty(htmlcontent) {
          //console.log( htmlcontent )
          //console.log( this.properties.content )
          this.properties.content = htmlcontent;
          this.onPropertyPaneFieldChanged( 'content', this.properties.content, htmlcontent );
          //console.log( this.properties.content )
        }
    

    将属性从ReactPortal 传递给Myportal 功能组件。

          <Myportal
            _mode={ this.props.mode }
            _content={ this.props.content }
            _updateWebPartContent={ this.props.updateWebPartContent } 
          />  
    

    用 props 对象更新了功能组件,添加了保存用户输入的钩子,并且还使用页面的当前模式来确定是否应该显示文本区域。

    const  Myportal = (props) => {   
      const [ content, setContent ] = React.useState(props._content);
    //abbreviated
      return (  
        <div className="App">
         { props._mode == 2 && <div>
           <textarea name="conent" id="conent" cols={30} rows={10} value={ props._content } onChange={ (evt) => { setContent(evt.target.value); } } 
     </textarea> <br />
      <button className="btn" onClick={ () => { props._updateWebPartContent(content) } } type="button" >Save Content</button> 
    </div> }
    
    
    <div className="modal-body">
      { props._content }
    </div>  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 2017-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多