当前位置: 首页 > news >正文

12. 对话框

一、对话框

  对话框窗口是一个用来完成简单任务或者和用户进行临时交互的顶层窗口,通常用于输入信息、确认信息或者提示信息。Qt Quick 提供了一系列的标准对话框,如 FileDialogColorDialogMessageDialogFontDialog 等,它们继承与 Qt.Dialogs.Dialog。Qt Quick 会首先使用平台相关的标准对话框,如果不可用,就使用自己实现的版本。

  Qt.Dialogs.Dialogvisible 属性默认是 false,即对话框是不可见的。如果我们要显示对话框,则需要调用 open() 方法或者手动将 visable 属性设置为 true。我们可以通过 title 属性 设置对话框的标题。如果我们要关闭对话框,可以使用 close() 方法。

  我们可以通过 modality 属性 设置对话框的模态性,它是一个枚举值,可以取值如下:

// 该对话框并非模态框,也不会阻止对其他窗口的输入操作
Qt.NonModal// 默认值,该对话框仅适用于单一窗口层次结构,并会阻止其父窗口、所有祖级窗口以及其父窗口和祖级窗口的所有兄弟窗口的输入操作
Qt.WindowModal// 该对话框与应用程序相关联,并会阻止所有窗口的输入操作
Qt.ApplicationModal

  当用户 点击确认按钮 后,会触发 accepted() 信号。当用户 点击取消按钮 时,会触发 rejected() 信号。

Qt.Dialogs.Dialog 为类型,无法使用它创建控件,会报 Dialog is not a type 错误。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

  • 阿里云 https://mirrors.aliyun.com/pypi/simple
  • 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
  • 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
  • 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple

二、文件对话框

  FileDialog 是 Qt Quick 中的文件对话框,它继承于 Qt.Dialogs.Dialog,它可以用来选择已有的文件、文件夹,支持单选、多选,也可以用来在保存文件或创建文件夹时让用户提供一个名字。

  我们可以通过 currentFolder 属性 设置打开文件对话框的初始目录。我们还可以通过 fileMode 属性 设置文件对话框的模式,它是一个枚举值,可以取值如下:

FileDialog.OpenFile                                                             // 该对话框用于选择一个现有的文件(默认选择的是当前文件)
FileDialog.OpenFiles                                                            // 该对话框用于选择多个已存在的文件
FileDialog.SaveFile                                                             // 该对话框用于选择任意文件,该文件无需存在

  我们可以通过 nameFilters 属性 设置文件过滤器nameFilters 是一个 字符串类型的列表,其中的每个字符串代表一种过滤器,它的语法格式如下:

nameFilters: ["过滤器名 (*.文件类型1 *.文件类型2 ...)"]

  在我们设置过滤器之后,我们可以使用 selectedNameFilter 属性 设置默认的过滤器。它是一个属性组,我们可以通过如下属性设置:

selectedNameFilter.index                                                        // 通过索引选择过滤器
selectedNameFilter.name                                                         // 通过过滤器名选择过滤器
selectedNameFilter.extensions                                                   // 通过文件扩展名选择过滤器
selectedNameFilter.globs                                                        // 通过通配符选择过滤器

  在我们选择单个文件后,选择的文件会保存在 selectedFile 属性中,如果我们选择了多个文件该属性指代第一个文件,此时我们可以使用 selectedFiles 属性,该属性是选择的文件的列表。

  我们新建一个 template.py 文件。

import sysfrom PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngineif __name__ == "__main__":app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例engine = QQmlApplicationEngine()                                            # 2.创建QML引擎对象engine.load("template.qml")                                                 # 3.加载QML文件sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

  我们新建一个 template.qml 文件。

import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.top: parent.topanchors.topMargin: 20anchors.horizontalCenter: parent.horizontalCenterfont.family: "楷体"font.pointSize: 14color: "#FF6666"}Button {id: buttonIdanchors.centerIn: parenttext: "文件对话框"font.pointSize: 24onClicked: {fileDialogId.open()                                                 // 打开文件对话框}}// 文件对话框FileDialog {id: fileDialogIdtitle: "选择文件"                                                        // 文件对话框的标题nameFilters: ["文本文件 (*.txt)", "图像文件 (*.jpg *.png)", "所有文件 (*)"] // 文件对话框的文件类型过滤器fileMode: FileDialog.OpenFiles                                           // 设置文件对话框的模式onAccepted: {// FileDialog的selectedFile保存了用户选择的文件路径,如果是多个文件,则显示第一个textId.text = selectedFile}}
}

三、文件夹对话框

  FolderDialog 对话框用来 选择一个文件夹,它继承于 Qt.Dialogs.Dialog。我们可以通过 currentFolder 属性 设置打开文件夹对话框的初始目录selectedFolder 属性 获取选中的文件夹路径

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.top: parent.topanchors.topMargin: 20anchors.horizontalCenter: parent.horizontalCenterfont.family: "楷体"font.pointSize: 14color: "#FF6666"}Button {id: buttonIdanchors.centerIn: parenttext: "文件夹对话框"font.pointSize: 24onClicked: {folderDialogId.open()                                                 // 打开文件对话框// 如果用户选择了文件夹,则将其设置为当前文件夹if (folderDialogId.selectedFolder) {folderDialogId.currentFolder = folderDialogId.selectedFolder}}}// 文件夹对话框FolderDialog {id: folderDialogIdtitle: "选择文件夹"                                                      // 文件对话框的标题onAccepted: {// FolderDialog的selectedFolder保存了用户选择的文件路径,如果是多个文件,则显示第一个textId.text = selectedFolder}}
}

四、颜色对话框

  ColorDialog 对话框用来 选择一个颜色,它继承于 Qt.Dialogs.Dialog。我们可以通过 selectedColor 属性 获取选择的颜色,通过 options 属性 设置颜色对话框的样式,它可以是以下值的集合:

ColorDialog.ShowAlphaChannel                                                    // 展示一个滑块以及用于输入alpha值的其他输入字段。
ColorDialog.NoButtons                                                           // 不要显示“打开”和“取消”按钮(适用于“实时对话框”)
ColorDialog.NoEyeDropperButton                                                  // 不要显示“吸管”按钮。此选项是在Qt6.6版本中添加的
ColorDialog.DontUseNativeDialog                                                 // 强制该对话使用非原生的快速实现方式

默认状态下,options 属性未设置任何选项。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.top: parent.topanchors.topMargin: 20anchors.horizontalCenter: parent.horizontalCenterfont.family: "楷体"font.pointSize: 32color: "#EE5599"text: "多情自古伤离别,此恨绵绵无绝期。"}Button {id: buttonIdanchors.centerIn: parenttext: "颜色对话框"font.pointSize: 24onClicked: {colorDialogId.open()                                                // 打开颜色对话框}}// 颜色对话框ColorDialog {id: colorDialogIdtitle: "选择颜色"                                                        // 颜色对话框的标题selectedColor: textId.color                                             // 初始化颜色对话框的颜色为文本框的颜色options: ColorDialog.ShowAlphaChannel                                   // 显示颜色对话框的Alpha通道onAccepted: {// ColorDialog的selectedColor保存了用户选择的颜色textId.color = selectedColor}}
}

options 属性应在显示对话框之前设置选项。在对话框可见的情况下设置选项,并不能保证能立即对对话框产生影响。

五、字体对话框

  FontDialog 对话框用来 选择一个字体,它继承于 Qt.Dialogs.Dialog。我们可以通过 selectedFont 属性 获取选择的字体,通过 options 属性 设置字体对话框的样式,.它是一个枚举值,它可以是以下值的集合:

// 默认情况下,未设置任何选项,这意味着所有字体类型都会显示出来,并且对话框中会显示标准的“选择”和“取消”按钮。
FontDialog.ScalableFonts                                                        // 显示可缩放字体
FontDialog.NonScalableFonts                                                     // 显示不可缩放字体
FontDialog.MonospacedFonts                                                      // 显示等宽字体
FontDialog.ProportionalFonts                                                    // 显示比例字体
FontDialog.NoButtons                                                            // 不要显示“打开”和“取消”按钮(适用于“实时对话框)
FontDialog.DontUseNativeDialog                                                  // 强制该对话使用非原生的快速实现方式

默认情况下,option 属性未设置任何选项,这意味着所有字体类型都会显示出来,并且对话框中会显示标准的“选择”和“取消”按钮。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.top: parent.topanchors.topMargin: 20anchors.horizontalCenter: parent.horizontalCenterfont.family: "楷体"font.pointSize: 32color: "#FF66CC"text: "科学技术的价值,在于使用者的意图。"}Button {id: buttonIdanchors.centerIn: parenttext: "字体对话框"font.pointSize: 24onClicked: {fontDialogId.open()                                                 // 打开字体对话框}}// 字体对话框FontDialog {id: fontDialogIdtitle: "选择字体"                                                        // 字体对话框的标题selectedFont: textId.font                                               // 初始化字体对话框的字体为文本框的字体onAccepted: {// FontDialog的selectedFont保存了用户选择的字体textId.font = selectedFont}}
}

  当我们运行程序点击按钮弹出字体对话框时,终端会输入如下内容,虽然不影响使用,但也不美观。

qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/qml/FontDialogContent.qml:223:16: QML Label: The current style does not support customization of this control (property: "label" item: Label_QMLTYPE_24(0x1c0ab7fdb90, parent=0x0, geometry=0,0 0x0 ?)). Please customize a non-native style (such as Basic, Fusion, Material, etc). For more information, see: https://doc.qt.io/qt-6/qtquickcontrols2-customize.html#customization-reference

  这个问题大致是说当前样式不支持对此控件的自定义设置,请自定义非原生样式(例如基本样式 Basic、融合样式 Fusion、材料样式 Material 等)。此时我们需要在加载 QML 文件之前,使用 QQuickStyle.setStyle() 方法设置样式。如果在加载 QML 之后设置,会报如下错误:

ERROR: QQuickStyle::setStyle() must be called before loading QML that imports Qt Quick Controls 2.

  修改 template.py 文件的内容。

import sysfrom PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtQuickControls2 import QQuickStyleif __name__ == "__main__":app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例engine = QQmlApplicationEngine()                                            # 2.创建QML引擎对象QQuickStyle.setStyle("Material")                                            # 3.设置QML引擎的样式engine.load("template.qml")                                                 # 4.加载QML文件sys.exit(app.exec())                                                        # 5.进入程序的主循环并通过exit()函数确保主循环安全结束

在显示对话框之前应先设置选项。在对话框可见的情况下设置选项,并不能保证能立即对对话框产生影响(这取决于选项以及所使用的平台)。

六、消息对话框

  MessageDialog 用来显示一个弹出消息框。我们可以使用 text 属性 设置要在消息对话框中显示的文本内容,使用 detailedText 属性 设置要在详细信息区域显示的文本内容informativeText 属性 包含了一段具有解释性的文字,该文字对消息进行了更详细的描述。

  我们可以使用 buttons 属性 设置使用的按钮集合,它可以是以下值的集合:

MessageDialog.NoButton                                                          // 默认值,该对话框中没有按钮MessageDialog.Ok                                                                // 一个通过AcceptRole定义的“确定”按钮
MessageDialog.Open                                                              // 一个通过AcceptRole定义的“打开”按钮
MessageDialog.Save                                                              // 一个通过AcceptRole定义的“保存”按钮
MessageDialog.SaveAll                                                           // 一个通过AcceptRole定义的“保存所有”按钮
MessageDialog.Retry                                                             // 一个通过AcceptRole定义的“重试”按钮
MessageDialog.Ignore                                                            // 一个通过AcceptRole.定义的“忽略”按钮MessageDialog.Cancel                                                            // 一个通过RejectRole定义的“取消”按钮
MessageDialog.Close                                                             // 一个通过RejectRole定义的“关闭”按钮
MessageDialog.Abort                                                             // 一个通过RejectRole定义的“中止”按钮MessageDialog.Discard                                                           // 根据不同的平台,会有一个“丢弃”或“不保存”按钮,其功能由DestructiveRole来定义MessageDialog.Apply                                                             // 一个通过ApplyRole定义的“应用”按钮MessageDialog.Reset                                                             // 一个通过ResetRole定义的“重置”按钮
MessageDialog.RestoreDefaults                                                   // 一个通过ResetRole定义的“恢复默认值”按钮MessageDialog.Help                                                              // 一个通过HelpRole定义的“帮助”按钮MessageDialog.Yes                                                               // 一个通过YesRole定义的“是”按钮
MessageDialog.YesToAll                                                          // 一个通过YesRole定义的“全部同意”按钮MessageDialog.No                                                                // 一个通过NoRole定义的“否”按钮
MessageDialog.NoToAll                                                           // 一个通过NoRole定义的“全部拒绝”按钮

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.top: parent.topanchors.topMargin: 20anchors.horizontalCenter: parent.horizontalCenterfont.family: "楷体"font.pointSize: 32color: "#FF66CC"}Button {id: buttonIdanchors.centerIn: parenttext: "消息对话框"font.pointSize: 24onClicked: {messageDialogId.open()                                              // 打开消息对话框}}// 消息对话框MessageDialog {id: messageDialogId// 消息对话框的按钮buttons: MessageDialog.Ok | MessageDialog.Canceltitle: "消息对话框"                                                      // 消息对话框的标题text: "确定要执行此操作吗?"                                              // 消息对话框的文本内容onAccepted: {textId.text = "用户点击了确定按钮"}onRejected: {// 用户点击了取消按钮textId.text = "用户点击了取消按钮"}}
}

七、自定义对话框

  要显示一个原生对话框,我们需要创建一个实现 QtQuick.Controls.Dialog 类的实例,然后再设置所需要的属性。在 QtQuick.Dialogs 模块中同样有一个 Dialog 控件,但是我们不能直接使用,会报 Dialog is not a type 错误。

  QtQuick.Controls.Dialogvisible 属性默认是 false,即对话框是不可见的。如果我们要显示对话框,则需要调用 open() 方法或者手动将 visable 属性设置为 true。我们可以通过 title 属性 设置对话框的标题head 属性 设置页眉footer 属性 设置页脚。如果我们要关闭对话框,可以使用 close() 方法。

  我们可以使用 standardButtons 属性 设置使用的按钮集合,它可以取值如下:

Dialog.NoButton                                                                 // 默认值,该对话框中没有按钮Dialog.Ok                                                                       // 一个通过AcceptRole定义的“确定”按钮
Dialog.Open                                                                     // 一个通过AcceptRole定义的“打开”按钮
Dialog.Save                                                                     // 一个通过AcceptRole定义的“保存”按钮
Dialog.SaveAll                                                                  // 一个通过AcceptRole定义的“保存所有”按钮
Dialog.Retry                                                                    // 一个通过AcceptRole定义的“重试”按钮
Dialog.Ignore                                                                   // 一个通过AcceptRole.定义的“忽略”按钮Dialog.Cancel                                                                   // 一个通过RejectRole定义的“取消”按钮
Dialog.Close                                                                    // 一个通过RejectRole定义的“关闭”按钮
Dialog.Abort                                                                    // 一个通过RejectRole定义的“中止”按钮Dialog.Discard                                                                  // 根据不同的平台,会有一个“丢弃”或“不保存”按钮,其功能由DestructiveRole来定义Dialog.Apply                                                                    // 一个通过ApplyRole定义的“应用”按钮Dialog.Reset                                                                    // 一个通过ResetRole定义的“重置”按钮
Dialog.RestoreDefaults                                                          // 一个通过ResetRole定义的“恢复默认值”按钮Dialog.Help                                                                     // 一个通过HelpRole定义的“帮助”按钮Dialog.Yes                                                                      // 一个通过YesRole定义的“是”按钮
Dialog.YesToAll                                                                 // 一个通过YesRole定义的“全部同意”按钮Dialog.No                                                                       // 一个通过NoRole定义的“否”按钮
Dialog.NoToAll                                                                  // 一个通过NoRole定义的“全部拒绝”按钮

  当用户 点击确认按钮 后,会触发 accepted() 信号。当用户 点击取消按钮 时,会触发 rejected() 信号。当用户点击对话框的按钮之后,我们可以通过 result 属性 获取用户点击的结果,如果值为 Dialog.Accepted 则表示 该对话框已被接受,如果值为 Dialog.Rejected 表示 该对话框已被拒绝

  当我们点击对话框外边,会发现对话框消失了,这相当于我们点击取消按钮关闭对话框。此时,我们可以通过 closePolicy 属性 设置对话框的关闭策略,它可以是以下值的集合:

Popup.NoAutoClose                                                               // 只有在手动发出关闭指令的情况下,该弹出窗口才会关闭
Popup.CloseOnPressOutside                                                       // 当鼠标在弹出窗口外按下时,该弹出窗口将会关闭
Popup.CloseOnPressOutsideParent                                                 // 当鼠标在其父元素外按下时,弹出窗口将会关闭
Popup.CloseOnReleaseOutside                                                     // 当鼠标在弹出外释放时,该弹出窗口将会关闭
Popup.CloseOnReleaseOutsideParent                                               // 当鼠标在其父元素外释放时,弹出窗口会关闭
Popup.CloseOnEscape                                                             // 当按下“退出”键且弹出窗口具有活动焦点时,该弹出窗口将会关闭

closePolicy 属性的默认值是 Popup.CloseOnEscape | Popup.CloseOnPressOutside

CloseOnPressCloseOnRelease 策略仅适用于弹出窗口之外的事件。也就是说,如果有两个弹出窗口打开,而第一个弹出窗口的策略为 Popup.CloseOnPressOutside,那么点击第二个弹出窗
口并不会导致第一个弹出窗口关闭。

  修改 template.qml 文件的内容。

import QtQuick.Window
import QtQuick.Controls// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {id: windowIdwidth: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Page {anchors.fill: parentheader: ToolBar {ToolButton {icon.name: "document-new"text: "添加信息"display: AbstractButton.TextUnderIcononClicked: {dialogId.open()                                             // 打开对话框}}}TextArea {id: textAreaIdanchors.fill: parentreadOnly: truefont.family: "楷体"font.pointSize: 32color: "#FF66CC"}}// 对话框Dialog {id: dialogIdwidth: 200anchors.centerIn: parent// 对话框是模态的,即用户必须先关闭对话框,才能继续与应用程序交互modal: true // 对话框的关闭策略closePolicy: Popup.NoAutoClosetitle: "添加信息"                                                        // 消息对话框的标题Column {id: columnIdanchors.fill: parentspacing: 10Text {id: nameTextIdfont.family: "楷体"font.pointSize: 16color: "#FF66CC"text: "请输入姓名:"}TextField {id: nameTextFieldIdwidth: columnId.widthfont: nameTextId.fontcolor: nameTextId.colorplaceholderText: "请输入姓名"}Text {font: nameTextId.fontcolor: nameTextId.colortext: "请选择性别:"}ComboBox {id: sexComboBoxIdwidth: columnId.widthmodel: ["保密", "男", "女"]font: nameTextId.font}Text {font: nameTextId.fontcolor: nameTextId.colortext: "请输入年龄:"}SpinBox {id: ageSpinBoxIdwidth: columnId.widtheditable: truefrom: 0to: 300stepSize: 1font: nameTextId.font}}footer: ToolBar {Row {anchors.right: parent.rightToolButton {id: resetToolButtonIdwidth: 60text: "重置"onClicked: {nameTextFieldId.text = ""sexComboBoxId.currentIndex = 0ageSpinBoxId.value = 0}}ToolButton {width: resetToolButtonId.widthtext: "取消"onClicked: {dialogId.reject()                                       // 拒绝对话框}}ToolButton {width: resetToolButtonId.widthtext: "确认"onClicked: {if (nameTextFieldId.text.trim() != "") {dialogId.accept()} else {nameTextFieldId.text = ""errorDialogId.open()}}}}}onAccepted: {textAreaId.text += (nameTextFieldId.text + " " + sexComboBoxId.currentText + " " + ageSpinBoxId.value + "\n")resetToolButtonId.clicked()}onRejected: {resetToolButtonId.clicked()}}Dialog {id: errorDialogIdanchors.centerIn: parentmodal: true standardButtons: Dialog.Ok                                              // 对话框的按钮title: "错误"                                                           // 对话框的标题Text {anchors.centerIn: parentfont.family: "楷体"font.pointSize: 16color: "#FF66CC"text: "姓名不能为空"}}
}
http://www.hskmm.com/?act=detail&tid=28297

相关文章:

  • 2024ICPC区域赛香港站
  • AI产品经理要了解的算法有哪些?
  • 一位印度小哥逆袭成为谷歌数据科学家的心路历程 - 教程
  • 基于selenium的网页自动搜索
  • MacOS Nginx
  • 缓存的击穿、雪崩、穿透在你项目中的场景是什么
  • [WC2021] 表达式求值
  • Set集合
  • AI时代下,如何看待“算法利维坦”?
  • JAVA - LinkedList 与 ArrayList 区别和 LinkedList 的四大接口解析
  • 苍穹外卖第三天(Swagger、@RequestParam和@RequestBody的使用场景、@PostMapping和@RequestMapping的区别、对象属性拷贝、@Insert注解)
  • Git 多账号管理
  • Hyper Server 2019安装I226-V网卡驱动
  • P10201 永恒
  • CF1209H tj
  • AirBattery - 在Mac上实时监控所有苹果设备电量
  • HTML学习日记
  • 10.10每日总结
  • 二分图与网络流 Trick
  • 10月10号
  • win11 系统如何进行硬盘分区?固态硬盘怎么分区?SSD 固态硬盘分区教程
  • 10/10
  • 数论(未完)
  • 没做完的题
  • 第十一天
  • JavaScriptDay1
  • 淘宝NPM镜像地址https://registry.npm.taobao.org不可用
  • 星星充电一面
  • 6 CF1034 div3 题解
  • 5 ABC413 题解