【Cloudscape云景】Cloudscape云景-React框架的使用-文档细读-云景的组件部分1

84 阅读6分钟

【Cloudscape云景】Cloudscape云景-React框架的使用-文档细读-云景的组件部分1

写在前面

网址如下: cloudscape.design/components/… Cloudscape共有72个组件, 我们笔记顺序按照组件分类记录.

image-20230811215846266

修改了一下文档中的实例代码, 给文档中实例代码一个使用场景, 这部分可能在Pattern里有. 我没看不知道

安装使用

全局样式包和open sans字体

npm install @cloudscape-design/global-styles

在app里导入

import "@cloudscape-design/global-styles/index.css"

安装组件

npm install @cloudscape-design/components

导入

import ComponentName from "@cloudscape-design/components/{component-name}"

或者这样导入

import { Button } from "@cloudscape-design/components"

全部代码样例如下

import { useState } from "react";
import Header from "@cloudscape-design/components/header";
import Container from "@cloudscape-design/components/container";
import SpaceBetween from "@cloudscape-design/components/space-between";
import Input from "@cloudscape-design/components/input";
import Button from "@cloudscape-design/components/button";

export default function App() {
  const [value, setValue] = useState("");

  return (
    <SpaceBetween size="m">
      <Header variant="h1">Hello World!</Header>

      <Container>
        <SpaceBetween size="s">
          <span>Start editing to see some magic happen</span>
          <Input
            value={value}
            onChange={(event) => setValue(event.detail.value)}
          />
          <Button variant="primary">Click me</Button>
        </SpaceBetween>
      </Container>
    </SpaceBetween>
  );
}

npm start后, 如果出现这样的页面证明成功配置

image-20230811214217269

react的严格模式, 会导致输出两次. 不是错误

布局部分

分类这部分比较难划分, 比如分类在A的组件也可以放在B中.

然后他甚至就在组件A的代码上加了一行就放到组件B里了~

有的没有写实例代码, 我就写一下demo.

应用程序布局 组件

  • 基本布局组件: 该组件适用于具有导航、内容区域和工具或帮助面板的应用程序。
  • 自定义头部或页脚: 通过 headerSelectorfooterSelector 属性指定。
  • 状态管理: 描述了如何控制导航、工具、分割面板等的状态。

所有的状态管理就是事件控制. 云景推荐使用可控状态管理,使用事件传递.

每个组件都分成了, properties 属性, Slots插槽, Event事件,Function函数. 区别如下:

属性: 用来配置组件, 可以用来配置组件外观, 行为, 内容等.navigationOpen 属性用来控制导航抽屉是否打开。

插槽: 将内容插入特定位置用来展示特定内容. 一个名为 navigation 的插槽,可以在其中插入自定义的导航菜单。

事件: 组件触发事件, 当事件触发组件会通过事件来相应. 如果导航抽屉被打开或关闭,组件可能会触发一个名为 onNavigationChange 的事件.

函数: 通常是组件提供的一些方法,用于执行特定的操作或任务。例如,组件可能提供了一个名为 closeNavigationIfNecessary 的函数,你可以在代码中调用这个函数来手动关闭导航抽屉。

函数和事件区别.... 一个是调用一个是特定情况触发, 挺简单的就是简单解释一下.

import React, { useState } from 'react';
import { AppLayout } from 'cloudscape'; // 导入路径可能需要调整

function MyApp() {
  const [navigationOpen, setNavigationOpen] = useState(false);
  const [toolsOpen, setToolsOpen] = useState(false);

  // 定义 ariaLabels
  const ariaLabels = {
    navigation: "Navigation drawer",
    navigationClose: "Close navigation drawer",
    navigationToggle: "Open navigation drawer",
    notifications: "Notifications",
    tools: "Help panel",
    toolsClose: "Close help panel",
    toolsToggle: "Open help panel"
  };

  // 处理导航切换事件
  const handleNavigationChange = (detail) => {
    setNavigationOpen(detail.open);
  };

  // 处理工具切换事件
  const handleToolsChange = (detail) => {
    setToolsOpen(detail.open);
  };

  return (
    <AppLayout
      ariaLabels={ariaLabels}
      navigationOpen={navigationOpen}
      toolsOpen={toolsOpen}
      onNavigationChange={handleNavigationChange}
      onToolsChange={handleToolsChange}
    >
      {/* 可以在此添加其他插槽内容,如内容、导航、工具等 */}
    </AppLayout>
  );
}

export default MyApp;

ariaLabels 这个标签是用来辅助ARIA(可访问富互联网):残疾人士等提供无障碍访问动态、可交互的技术.

Box组件

Box组件主要就是提供了一些, 段落文字, H1文字, 代码块, 值得一提的是这里放了按钮的布局

Split panel组件

image-20230813044723535

这个图案意思是, 选中资源后, 会在下侧展示分割组件;

原则: 不要使用分割组件来显示帮助信息, 不要使用分割面板来代替详情页.

它的作用是显示资源详情信息. (详情页会有其他交互, 这里是没有交互,只做反显)

Wizard向导组件

import * as React from "react";
import Wizard from "@cloudscape-design/components/wizard";
import {Container, FormField, Input, SpaceBetween, Header, Link, Box, ColumnLayout, Button} from "@cloudscape-design/components";


export default () => {
    const [
        activeStepIndex,
        setActiveStepIndex
    ] = React.useState(0);
    return (
        <Wizard
            i18nStrings={{
                stepNumberLabel: stepNumber =>
                    `Step ${stepNumber}`,
                collapsedStepsLabel: (stepNumber, stepsCount) =>
                    `Step ${stepNumber} of ${stepsCount}`,
                skipToButtonLabel: (step, stepNumber) =>
                    `Skip to ${step.title}`,
                navigationAriaLabel: "Steps",
                cancelButton: "Cancel",
                previousButton: "Previous",
                nextButton: "Next",
                submitButton: "Launch instance",
                optional: "optional"
            }}
            onNavigate={({ detail }) =>
                setActiveStepIndex(detail.requestedStepIndex)
            }
            activeStepIndex={activeStepIndex}
            allowSkipTo
            isLoadingNextStep
            steps={[
                {
                    title: "Choose instance type",
                    info: <Link variant="info">Info</Link>,
                    description:
                        "Each instance type includes one or more instance sizes, allowing you to scale your resources to the requirements of your target workload.",
                    content: (
                        <Container
                            header={
                                <Header variant="h2">
                                    Form container header
                                </Header>
                            }
                        >
                            <SpaceBetween direction="vertical" size="l">
                                <FormField label="First field">
                                    <Input />
                                </FormField>
                                <FormField label="Second field">
                                    <Input />
                                </FormField>
                            </SpaceBetween>
                        </Container>
                    )
                },
                {
                    title: "Add storage",
                    content: (
                        <Container
                            header={
                                <Header variant="h2">
                                    Form container header
                                </Header>
                            }
                        >
                            <SpaceBetween direction="vertical" size="l">
                                <FormField label="First field">
                                    <Input />
                                </FormField>
                                <FormField label="Second field">
                                    <Input />
                                </FormField>
                            </SpaceBetween>
                        </Container>
                    ),
                    isOptional: true
                },
                {
                    title: "Configure security group",
                    content: (
                        <Container
                            header={
                                <Header variant="h2">
                                    Form container header
                                </Header>
                            }
                        >
                            <SpaceBetween direction="vertical" size="l">
                                <FormField label="First field">
                                    <Input />
                                </FormField>
                                <FormField label="Second field">
                                    <Input />
                                </FormField>
                            </SpaceBetween>
                        </Container>
                    ),
                    isOptional: true
                },
                {
                    title: "Review and launch",
                    content: (
                        <SpaceBetween size="xs">
                            <Header
                                variant="h3"
                                actions={
                                    <Button
                                        onClick={() => setActiveStepIndex(0)}
                                    >
                                        Edit
                                    </Button>
                                }
                            >
                                Step 1: Instance type
                            </Header>
                            <Container
                                header={
                                    <Header variant="h2">
                                        Container title
                                    </Header>
                                }
                            >
                                <ColumnLayout
                                    columns={2}
                                    variant="text-grid"
                                >
                                    <div>
                                        <Box variant="awsui-key-label">
                                            First field
                                        </Box>
                                        <div>Value</div>
                                    </div>
                                    <div>
                                        <Box variant="awsui-key-label">
                                            Second Field
                                        </Box>
                                        <div>Value</div>
                                    </div>
                                </ColumnLayout>
                            </Container>
                        </SpaceBetween>
                    )
                }
            ]}
        />
    );
}

image-20230813050910932

这里主要记录一下, isLoadingNextStep.

主要在父组件里进行异步操作,案例代码如下

export default () => {
  const [activeStepIndex, setActiveStepIndex] = React.useState(0);
  const [isLoadingNextStep, setIsLoadingNextStep] = React.useState(false);

  const loadNextStep = async () => {
    setIsLoadingNextStep(true);
    
    // 这里可以放置获取下一步数据的异步代码
    // 例如,调用API或执行其他异步操作

    setIsLoadingNextStep(false);
  };

  // 当用户导航到下一步时,触发加载
  const handleNavigate = ({ detail }) => {
    setActiveStepIndex(detail.requestedStepIndex);
    loadNextStep();
  };

  return (
    <Wizard
      isLoadingNextStep={isLoadingNextStep}
      onNavigate={handleNavigate}
      // 其他属性和子组件
    />
  );
};

action部分

按钮

image-20230813051151591

按钮下拉菜单Button dropdown

image-20230813051227270

Copy to clipboard 复制到剪切板组件

import React from 'react';
import { Box, Button, Popover, StatusIndicator } from '@cloudscape-design/components';
// import './custom.scss';

export default () => (
    <span className="custom-wrapping">
    <Box margin={{ right: 'xxs' }} display="inline-block">
      <Popover
          size="small"
          position="top"
          triggerType="custom"
          dismissButton={false}
          content={<StatusIndicator type="success">[Name of the content] copied</StatusIndicator>}
      >
        <Button
            variant="inline-icon"
            iconName="copy"
            ariaLabel="Copy [name of the content]"
            onClick={() => {
                navigator.clipboard.writeText('text-that-gets-copied');
            }}
        />
      </Popover>

    </Box>
    text-that-gets-copied
        
  </span>

);

主要就是修改这部分代码

image-20230813052340964

类似实现如下

const textToCopy = "这是我想复制的文本";
// ...

<Button
  variant="inline-icon"
  iconName="copy"
  ariaLabel="Copy text"
  onClick={() => {
    navigator.clipboard.writeText(textToCopy);
  }}
/>

写的完整一些, 一般在实际中会获取某个dom的值.

import React, {useRef} from 'react';
import { Box, Button, Popover, StatusIndicator } from '@cloudscape-design/components';
export default () => {
    const inputRef = useRef(null);

    const handleCopyClick = () => {
        if (inputRef.current) {
            navigator.clipboard.writeText(inputRef.current.value);
        }
    };

    return (
        <span className="custom-wrapping">
        <Box margin={{right: 'xxs'}} display="inline-block">
        <Popover
          size="small"
          position="top"
          triggerType="custom"
          dismissButton={false}
          content={<StatusIndicator type="success">[Name of the content] copied</StatusIndicator>}
      >
        <Button
            variant="inline-icon"
            iconName="copy"
            ariaLabel="Copy [name of the content]"
            onClick={() => {
                navigator.clipboard.writeText(inputRef.current.value);
            }}
        />
      </Popover>

    </Box>
            <input ref={inputRef} type="text" placeholder="输入要复制的文本"/>

  </span>
    );
};

Segmented control分段控制组件

import * as React from "react";
import SegmentedControl from "@cloudscape-design/components/segmented-control";

export default () => {
  const [selectedId, setSelectedId] = React.useState(
    "seg-1"
  );
  return (
    <SegmentedControl
      selectedId={selectedId}
      onChange={({ detail }) =>
        setSelectedId(detail.selectedId)
      }
      label="Default segmented control"
      options={[
        { text: "Segment 1", id: "seg-1" },
        { text: "Segment 2", id: "seg-2" },
        { text: "Segment 3", id: "seg-3" }
      ]}
    />
  );
}

这里要控制选项卡显示不同内容可以用下面的代码

import * as React from "react";
import SegmentedControl from "@cloudscape-design/components/segmented-control";

export default () => {
  const [selectedId, setSelectedId] = React.useState("seg-1");

  let content;
  switch (selectedId) {
    case "seg-1":
      content = <div>内容1</div>;
      break;
    case "seg-2":
      content = <div>内容2</div>;
      break;
    case "seg-3":
      content = <div>内容3</div>;
      break;
    default:
      content = <div>默认内容</div>;
  }

  return (
    <div>
      <SegmentedControl
        selectedId={selectedId}
        onChange={({ detail }) => setSelectedId(detail.selectedId)}
        label="Default segmented control"
        options={[
          { text: "Segment 1", id: "seg-1" },
          { text: "Segment 2", id: "seg-2" },
          { text: "Segment 3", id: "seg-3" }
        ]}
      />
      {content} {/* 这里渲染选中选项卡对应的内容 */}
    </div>
  );
};

显示结果如下

image-20230813054114967

Input部分

AttributeEditor属性编辑组件

代码如下:

import * as React from "react";
import AttributeEditor from "@cloudscape-design/components/attribute-editor";
import {Input} from "@cloudscape-design/components";
export default () => {
    const [items, setItems] = React.useState([
        { key: "some-key-1", value: "some-value-1" },
        { key: "some-key-2", value: "some-value-2" }
    ]);
    return (
        <AttributeEditor
            onAddButtonClick={() => setItems([...items, {}])}
            onRemoveButtonClick={({
                                      detail: { itemIndex }
                                  }) => {
                const tmpItems = [...items];
                tmpItems.splice(itemIndex, 1);
                setItems(tmpItems);
            }}
            items={items}
            addButtonText="Add new item"
            definition={[
                {
                    label: "Key",
                    control: item => (
                        <Input
                            value={item.key}
                            placeholder="Enter key"
                        />
                    )
                },
                {
                    label: "Value",
                    control: item => (
                        <Input
                            value={item.value}
                            placeholder="Enter value"
                        />
                    )
                }
            ]}
            removeButtonText="Remove"
            empty="No items associated with the resource."
        />
    );
}

实现效果如下

image-20230813055220927

这个组件允许用户动态添加、编辑和删除键值对。用户可以点击添加按钮来创建新的键值对,然后在文本框中输入键和值。用户还可以点击移除按钮来删除特定的键值对。

需要注意的是,虽然这个示例允许用户在界面上添加、删除和查看键值对,但它并没有实现修改这些键值对的逻辑。你可能需要添加更多代码来处理用户输入的变化,例如通过在 Input 组件上使用 onChange 属性来监听和保存用户的输入。