在管理界面控件中使用Gutenberg块组件

时间:2020-03-15 作者:Andrew

我问了一个previous question, 得到了一个有用的答案,这让我走了很长的路。目前的问题与此无关,但IMO反映出,对于我们这些不熟悉javascript的一些细微差别、对Gutenberg开发来说是全新的、但仍需要到处调整新的Wordpress的人来说,适合他们的文档太少了。我将首先声明我是javascript新手,并怀疑我的问题与此相关。

如前一个问题所述,我正在修改自定义帖子类型的管理编辑屏幕中的特色图像控件。我想添加一个复选框和一个文本输入字段来捕获用户提供的资源URL。我有一个加载到相关页面上的javascript文件,以及使用Gutenberg、JSX和所有基于react的组件(react-devel、react-dom、babel、wp blocks、wp-i18n、wp-element、wp-editor、wp-hooks)所需的所有依赖项。我还准备了一个过滤器来设置我的脚本类型。js文件转换为“text/babel”,以便JSX正确解释。我想我没有错过任何东西。

这是我的一个版本。显示标题和富文本字段的js文件。这不是我想要的,但它确实有效,javascript控制台中没有任何抱怨。在这一点上,我仍在努力找出我需要的构建块,以及如何使用它们。

window.addEventListener("load", function(event){
  console.log("featured_image.js loaded and functional...");
});

const el = wp.element.createElement;
// const withState = wp.compose.withState;
const setState = wp.data.setState;
const withSelect = wp.data.withSelect;
const withDispatch = wp.data.withDispatch;
const { CheckboxControl } = wp.editor;
const { RichText } = wp.editor;
const { useState } = wp.element;
const { TextControl } = wp.components
const { withState } = wp.compose;


wp.hooks.addFilter(
    \'editor.PostFeaturedImage\',
    \'dsplugin/featured-image-as-video\',
    wrapPostFeaturedImage
);


//this works
const MyRichTextField =
    <RichText
      placeholder="placeholder text"
    />
;

function wrapPostFeaturedImage( OriginalComponent ) {
    return function( props ) {
        return (
            el(
                wp.element.Fragment,
                {},
                // \'Prepend above\',
                el(
                    OriginalComponent,
                    props
                ),
                <strong>this is a test</strong>,
                // MyCheckboxControl
                MyRichTextField
            )
        );
    }
}
下面是输出的样子。。。

featured image sidebar area

但是,当我尝试添加checkboxControl时,使用与RichText字段相同的方法时,我遇到了问题。此代码。。。

const MyCheckboxControl =
    const [ isChecked, setChecked ] = useState( true );
    <CheckboxControl
        heading="User"
        label="Is author"
        help="Is the user a author or not?"
        checked={ isChecked }
        onChange={ setChecked }
    />
;
不起作用。javascript控制台显示。。。

SyntaxError: ... Unexpected token (28:4)
  27 | const MyCheckboxControl = () => (
> 28 |     const [ isChecked, setChecked ] = useState( true );
     |     ^
  29 |     <CheckboxControl
  30 |         heading="User"
  31 |         label="Is author"
然而,这正是Gutenberg documentation 说我们应该实现CheckboxControl。至少在创建块时。侧边栏中的内容是否有所不同?我尝试了一个文本控件,如下所示。。。

const MyTextControl = withState( {
    className: \'\',
} )( ( { className, setState } ) => (
    <TextControl
        label="Additional CSS Class"
        value={ className }
        onChange={ ( className ) => setState( { className } ) }
    />
) );
上述定义没有语法错误,但当我尝试在wrapPostFeaturedImage()函数中使用它时,如下所示:

function wrapPostFeaturedImage( OriginalComponent ) {
    return function( props ) {
        return (
            el(
                wp.element.Fragment,
                {},
                // \'Prepend above\',
                el(
                    OriginalComponent,
                    props
                ),
                <strong>this is a test</strong>,
                // MyCheckboxControl
                MyTextControl
            )
        );
    }
}
我在控制台中收到以下警告,在“这是一个测试”标题后没有显示任何内容。

Warning: Functions are not valid as a React child. 
This may happen if you return a Component instead of <Component /> from render. 
Or maybe you meant to call this function rather than return it.
我觉得我与这里发生的事情有着根本的脱节。我错过了什么?

2 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

Warning (或请其他读者注意):前面有很多JavaScript代码。。事实上,这里没有PHP。因此,我希望您在阅读此答案之前已经具备一些JavaScript技能谢谢

我还准备了一个过滤器,用于设置.js 文件收件人text/babel 因此JSX的解释是正确的。我想我没有错过任何东西。

但对于生产使用,您应该build your script 或者不要使用JSX 因为没有编译器的帮助,浏览器无法理解语法。此外,在制作或“标准”/实时WordPress网站中,您应该使用text/babel 类型,因此无需加载/包含Babel编译器,因为即使React本身也表示the compiler makes your site slow. 因此,仅将其用于开发和测试目的。

Update Mar 16 2020 (regarding above statement): 不,我的意思是不建议在代码中使用JSX。事实上,我确实推荐它,因为它更容易创建,例如strong 使用JSX的元素比使用wp.element.createElement() 在古腾堡或React.createElement() 在本机React应用程序中:

创建strong JSX中的元素:

<strong className="foo">
  It\'s easy, pretty much like regular HTML markup.
  But you can use JS expressions: 2 * 5 = { 2 * 5 }.
</strong>
strong 元素“正常方式”(非JSX):

// In native React, you\'d use React.createElement().
// Not super hard, but how about nested elements?
wp.element.createElement( \'strong\', {
  className: \'foo\'
}, \'Some text here. 2 * 5 = \', 2 * 5 );
I do not suggest包含浏览器内JSX预处理器like Babel 在您的网站上。如果这不是你所指的,对不起,但我真正想说的是,if 在脚本中使用JSX,强烈建议在生产/现场使用之前先构建脚本。但是,如果您想在JSX中开发,或者对于不涉及复杂元素的简单内容,您可以选择不在JSX中开发。

我希望现在有意义了?(Note: 我于2020年4月2日改写了上述段落。)

代码中的问题MyCheckboxControl 问题不是你的错,但不幸的是,古腾堡团队在example. 正确的代码应为:

Update Apr 03 2020: 因此,代码于2020年3月17日更正。但今天,我注意到它又出现了(所以我不再说它是固定的,即使它已经固定了。相反,对于问题中的代码,下面是正确的。

const MyCheckboxControl = () => {
    const [ isChecked, setChecked ] = useState( true );
    return (
        <CheckboxControl
            heading="User"
            label="Is author"
            help="Is the user a author or not?"
            checked={ isChecked }
            onChange={ setChecked }
        />
    );
};
wp.element.createElement():

Update Apr 02 2020: 其实你可以;只需确保正确完成即可&mdash;如果您的站点中没有包含任何JSX预处理器,那么请确保构建脚本,以便将JSX转换为大多数浏览器都能理解的格式。对于@Andrew,我主要修改了这个答案,以便其他人不会因为上述陈述而得到虚假信息。:)

附加注释(作为对您答案的回应)

所以您是对的const { CheckboxControl } = wp.editor; //incorrect, 我没有注意到,因为我直接使用wp.components.CheckboxControl.

但是,以下方面:

const el = wp.element.createElement;
const setState = wp.data.setState;
const withSelect = wp.data.withSelect;
const withDispatch = wp.data.withDispatch;
const { CheckboxControl } = wp.editor;
const { RichText } = wp.editor;
const { useState } = wp.element;
const { TextControl } = wp.components
const { withState } = wp.compose;
可以是made simpler:

const el = wp.element.createElement;
const { setState, withSelect, withDispatch } = wp.data;
const { CheckboxControl, TextControl } = wp.components;
const { RichText } = wp.editor;
const { useState } = wp.element;
const { withState } = wp.compose;
一、 e.使用const { <property>, <property>, <property>, ... } = myObject; 哪里<property> 是对象中的属性名称。例外情况el 自从wp.element.el 未定义。

创建React/Gutenberg组件实际上可以查看React的官方文档,如this 对于创建组件和使用组件的prop(ertie)s。例如,以下内容(使用JSX和)均有效:

// Using normal function.
function Welcome( props ) {
  return <h1>Hello, {props.name}</h1>;
}

// Using the class method.
class Welcome extends wp.element.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

// Using "arrow" function.
const Welcome = ( props ) => <h1>Hello, {props.name}</h1>;

// No props, so here it\'s OK to use no function wrapping.
const Welcome = <h1>Hello <i>World</i>!</h1>;

// Note: If there are DIRECT child elements, wrap in a container like a Fragment.
const Welcome =
    <>
        <h1>Hello World!</h1>
        <p>Foo bar baz</p>
    </>
;
对于那些不知道或不熟悉所谓的“箭头函数”(在ESNext/ES6中)的人,请检查Arrow function expressions on MDN.

访问组件属性/道具

与函数/组件道具一样,函数/组件道具实际上是一个函数参数/参数,无论是React、Gutenberg、Vue、jQuery等库,您都可以以相同的方式访问函数参数。很抱歉,我不能在这里提供关于访问参数的不同方法的教程,但是MDN reference 会是你最好的朋友。尽管如此,我希望这些(非常简单的)示例能够帮助您:

// Log all parameters passed to the function. Similar to func_get_args() in PHP.
function foo() {
    console.log( ...arguments );
}

function foo( props ) {
    console.log( props );
}

// You should pass an object to the function.
function foo( { a, b } ) {
    console.log( { a, b } );
}

// All of the above show {a: 1, b: "two"} when you do:
foo( { a: 1, b: \'two\' } );

function foo2( a, b, ...more ) {
    console.log( a, b, more );
}
// This one would show: 1 "two" (3) [3, "four", false]
foo2( 1, \'two\', 3, \'four\', false )
下面是一个基于类的组件的示例,您可以使用this.props 要访问组件的道具,尽管您确实可以使用上述任何方法访问道具:

class Foo extends wp.element.Component {
    constructor() {
        super( ...arguments ); // you must call super()
        console.log( this.props );
    }
    /* You can also do so:
    constructor( props ) {
        super( ...arguments );
        console.log( props, this.props === props ); // the condition should return true
    }

    // Or like so:
    constructor( { name, place } ) { // unpack the props
        super( ...arguments );
        console.log( name, place );
    }
    */

    render() {
        const { name, place } = this.props;
        return <h1>Hello, { name } from { place }!</h1>;
    }
}

// The following JSX would output <h1>Hello, John from Pluto!</h1>
// And in the console, you\'d see: {name: "John", place: "Pluto"}
//<Foo name="John" place="Pluto" />
<所以我希望这个(修改后的)答案能帮助你(更多),真的,说到古腾堡,你最好的朋友是React\'s official site, MDN web docs for JavaScript 当然还有古腾堡(方块编辑器)handbook.

快乐的编码!

SO网友:Andrew

上面的答案很有帮助。然而,为了其他人的利益,我想我应该对此进行扩展并发布更多细节。

首先是very 正确导入要使用的组件很重要。上面的CheckBoxControl原始代码中有一个错误。

const { CheckboxControl } = wp.editor; //incorrect
应该是

const { CheckboxControl } = wp.component;
萨莉说的没错,古腾堡的文档有缺陷。我已经创建了一个拉请求和她的更正,希望这将很快得到修复。但更一般地说,实际上有几种正确的方法可以将组件表示为常量变量,以便在代码中的其他地方使用。考虑以下等效声明。

//all three of these components work if used as <MyTestComponent />
const MyTestComponent1 = () =>
  <div>
    <h4>Howdy Doody1</h4>
  </div>
;
const MyTestComponent2= () => (
  <div>
    <h4>Howdy Doody2</h4>
  </div>
);
const MyTestComponent3= () => {
  return(
    <div>
      <h4>Howdy Doody3</h4>
    </div>
  )
};

两者之间只有细微的区别,但对于像我这样的javascript/React新手来说,以一种方式在某处看到一个示例,以另一种方式在某处看到另一个示例,是非常令人困惑的。

最后,这可能是最令人困惑的,以下也是等效的:

//all three of these forms work if used as <MyTestComponent />
const MyTestComponent1 = (props) =>
  <div>
    <h4>Howdy Doody1</h4>
    <p>{props.message1} {props.message2}</p>
  </div>
;

const MyTestComponent2= ({message1, message2}) => (
  <div>
    <h4>Howdy Doody2</h4>
    <p>{message1} {message2}</p>
  </div>
);
React(Gutenberg对其进行了非常细微的伪装)使用props对象来保存有关组件的属性。你不必申报,它只是神奇地存在着。在第一个示例(MyTestComponent1)中,props对象是显式的。然而,在第二个示例(MyTestComponent2)中,它是隐式的,并且是假定的。从我在在线示例代码中看到的情况来看,第二种形式更加常见。

换句话说,在MyTestComponent2中,message1和message2仍然是props对象的属性,组件声明的两种形式是等效的。。。但你应该知道这一点。

无论如何希望这对其他人有所帮助。

相关推荐