Blazor Modal对话框编辑器

Blazor Modal对话框编辑器目录介绍代码库控制 SPA 导航建立对话 ModalDialog1 razorSite css 运行版本 1 版本 2Site js 模态对话框运行版本 2 版本 3ModalResult 和 ModalResultT 对话模态对话框天气组件天气编辑器 FetchDataMod 总结介绍为了设置本文的上下文 自 Blazor 首次发布以来 已经有许多关于如何处理编辑表单

目录

介绍

代码库

控制SPA导航

建立对话

ModalDialog1

FetchData1

Site.css

运行版本1

版本2

Site.js

模态对话框

运行版本2

版本3

ModalResult和ModalResultType

ModalOptions

IModal对话

模态对话框

天气组件

天气编辑器

FetchDataModal

总结


介绍

为了设置本文的上下文,自Blazor首次发布以来,已经有许多关于如何处理编辑表单的讨论、文章和建议。特别是在离开脏表单时如何停止或至少警告用户。这个问题并非特定于Blazor:所有单页应用程序和网站都面临相同的挑战。

在经典的Web表单中,每个导航都是获取或发布回服务器的信息。我们可以使用内置window.beforeunload事件来警告用户他们页面上有未保存的数据。不太好,但至少有一些好处——我们将在以后使用。这项技术在SPA中不适用。在外人看来,导航事件不是。NavigationManager拦截页面中的任何导航尝试,触发其自己的LocationChanged事件并下沉请求。连接到这个事件中的Router完成了它的魔法,并加载新的组件集到页面中。没有真正的浏览器导航发生,因此浏览器没有任何beforeunload事件可捕获。

由程序员决定编写代码来阻止用户离开肮脏的表格。当您的应用程序依赖于URL导航借口时,说起来容易做起来难。工具栏、导航侧栏和许多按钮会提交URL以便在应用程序中导航。考虑现成的Blazor模板。左侧导航栏中的所有链接都位于顶部栏中。

就个人而言,我对整个路由难题都存在严重的问题:SPA是一种应用程序,而不是网站,但是我认为其必须是其中的一小部分!本文适用于大多数。

我遇到的所有NetCore 3.1解决方案都是一种形状或另一种形状的杂物,我自己创建了一个以上的形状。社区希望的是NetCore 5中的更改,特别是一些NavigationManager取消或阻止导航请求的额外功能。那没有发生:我不认为团队对于正确的解决方案有共识,所以我们回到正题。

我在本文中介绍的是我针对该问题的最新方法。它不是完美的,但我认为在获得一些新的浏览器标准(允许切换到SPA模式并控制工具栏导航)之前,我们不会获得接近完美的解决方案。

Blazor Modal对话框编辑器

代码库

可以在Github上的CEC.Blazor.Editor上找到该代码。

控制SPA导航

第一个挑战——如何阻止用户访问标准页面上的任何按钮/链接导航内容?

  1. 建立一个自定义NavigationManager。这不是一个坏主意,但这是Blazor基础架构的核心部分,带来了许多后果。我说清楚了。
  2. 建立一个自定义Router。也不是一个坏主意。我已经做到了,在Nuget上有一个已发布的软件包,一个Github Repo和此站点上的一篇文章。我仍然想摆脱一些问题。
  3. 构建一个导航组件,在整个应用程序中使用它进行所有导航。同样不是一个坏主意,但是需要严格的纪律以在任何团队环境中执行。
  4. 使用模态对话框,锁定表单的其余部分。我的首选选项以及我将在此处进行探索和开发的选项。

注意——这里的大多数代码都是实验性的——绝对不适合生产。几乎没有错误检查等等。尝试保持透明性是民权主义者。

建立对话

首先,我们建立一个基本的模态对话框。这与CSS框架无关。欢迎您采用它以适合Bootstrap等。

ModalDialog1

将一个razor组件添加到共享中,并使用一个名为ModalDialog1的文件后面的代码。添加以下代码。它是天气预报的伪装编辑。

是的,这是Bootstrap

@if (this.Display) { 
     }
using Microsoft.AspNetCore.Components; namespace CEC.Blazor.Editor.Shared { public partial class ModalDialog1 : ComponentBase { public bool Display { get; private set; } public void Show() { this.Display = true; this.InvokeAsync(this.StateHasChanged); } public void Hide() { this.Display = false; this.InvokeAsync(this.StateHasChanged); } } }

笔记

  1. 我们用Show来控制模式的显示。无需JavaScriptCSS即可对其进行切换。
  2. 我们有两个public方法ShowHide对话框。
  3. 我们调用StateHasChanged以渲染组件。没有外部触发器可以重新渲染组件(没有更改参数,也没有发生UI事件),因此我们需要强制进行渲染。评论他们,看看会发生什么!

FetchData1

我们使用FetchData页面组件作为模板,因此在其中创建一个新的Razor组件Pages并调用它FetchData1。在文件后面创建一个FetchData1.razor.cs代码。切记将类标记为partial

添加以下代码:

@page "/fetchdata1" @using CEC.Blazor.Editor.Data 

Weather forecast

This component demonstrates fetching data from a service.

@if (forecasts == null) {

Loading...

} else { @foreach (var forecast in forecasts) { }
Date Temp. (C) Temp. (F) Summary
@forecast.Date.ToShortDateString() @forecast.TemperatureC @forecast.TemperatureF @forecast.Summary
}
using CEC.Blazor.Editor.Data; using CEC.Blazor.Editor.Shared; using Microsoft.AspNetCore.Components; using System; using System.Threading.Tasks; namespace CEC.Blazor.Editor.Pages { public partial class FetchData1 : ComponentBase { [Inject] WeatherForecastService ForecastService { get; set; } private WeatherForecast[] forecasts; private ModalDialog1 Modal { get; set; } protected override async Task OnInitializedAsync() { forecasts = await ForecastService.GetForecastAsync(DateTime.Now); } private void ShowModalDialog() { this.Modal.Show(); } } }

笔记

  1. 我们已在每行中添加了一个编辑按钮,以访问编辑器(链接到)ShowModalDialog
  2. 我们已经在页面底部添加了一个ModalDialog1组件,并将@ref添加到属性中。
  3. 我们添加了一个ModalDialog1属性。
  4. 我们添加了一种ShowModalDialog方法来打开模态对话框

在构建之前,我们需要做一些最后的更改。

我们需要在NavMenu中添加一个指向新页面的链接。

Site.css

我们需要将模态对话框css添加到站点css文件中。我们可以将此代码移动到组件css文件中进行生产,但在site.css即时编辑更容易。

div.modal-background { display: block; position: fixed; z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } div.modal-content { background-color: #fefefe; margin: 10% auto; padding: 10px; border: 2px solid #888; width: 90%; }

运行版本1

运行该应用程序,然后转到FetchData1。点击一个编辑按钮。基础页面上的所有链接均被禁用。三种退出路径是:

  1. 关闭按钮。
  2. 输入一个新的URL
  3. 关闭浏览器选项卡或关闭浏览器。

我知道有第四,第五(杀死进程,按电源开关),但是没有什么可以阻止这些。

Blazor Modal对话框编辑器

版本2

现在关闭这三个退出。我已经在仓库中创建了version2文件,但是您可以根据需要更新原始文件。

Site.js

js文件夹添加到wwwroot,然后添加一个site.js文件。

添加以下代码。

  1. 我们定义了window.cecblazor_showExitDialog——一个事件函数,它会弹出浏览器Are You Sure实现。不同浏览器的外观有所不同,但总是会提出某种退出挑战。
  2. 我们定义了window.cecblazor_setEditorExitCheck,其通过BlazorJsInterop调用的方法,以添加和删除事件处理程序。
window.cecblazor_setEditorExitCheck = function (show) { if (show) { window.addEventListener("beforeunload", cecblazor_showExitDialog); } else { window.removeEventListener("beforeunload", cecblazor_showExitDialog); } } window.cecblazor_showExitDialog = function (event) { event.preventDefault(); event.returnValue = "There are unsaved changes on this page. Do you want to leave?"; }

我们需要将此js文件包含在我们的应用程序中。更新Host._cshtml

..... 


模态对话框

我们需要向模式对话框添加更多功能,以模拟脏表单。更新ModalDialog中的按钮行。

 
    
@if (this.DirtyExit) { } else { }

更新文件添加背后的代码:

  1. 布尔属性——IsDirtyIsLocked以及DirtyExit——向控制如果控制状态和按钮显示。
  2. 注入IJSRuntime以访问JSInterop
  3. CSS字符串属性来控制按钮CSS
  4. 各种按钮事件处理程序,用于切换状态。您应该能够自己算出逻辑。
  5. SetPageExitCheck 与页面JS进行交互,并打开和关闭浏览器退出挑战。
using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace CEC.Blazor.Editor.Shared { public partial class ModalDialog2 : ComponentBase { [Inject] private IJSRuntime _js { get; set; } public bool Display { get; private set; } public bool IsDirty { get; set; } public bool IsLocked { get; private set; } private bool DirtyExit { get; set; } private string DirtyButtonCss => this.IsDirty ? "btn-danger" : "btn-success"; private string DirtyButtonText => this.IsDirty ? "Set Clean" : "Set Dirty"; public void Show() { this.Display = true; this.InvokeAsync(this.StateHasChanged); } public void Hide() { if (this.IsDirty) this.DirtyExit = true; else this.Display = false; this.InvokeAsync(this.StateHasChanged); } public void DirtyHide() { this.Display = false; this.DirtyExit = false; if (this.IsDirty) { this.IsDirty = false; CheckLock(); } this.InvokeAsync(this.StateHasChanged); } public void CancelHide() { this.DirtyExit = false; this.InvokeAsync(this.StateHasChanged); } public void SetDirty() { if (this.IsDirty) this.DirtyExit = false; this.IsDirty = !this.IsDirty; this.CheckLock(); this.InvokeAsync(this.StateHasChanged); } public void SetPageExitCheck(bool action) { _js.InvokeAsync 
    
      ("cecblazor_setEditorExitCheck", action); } public void CheckLock() { if (this.IsDirty && !this.IsLocked) { this.IsLocked = true; this.SetPageExitCheck(true); } else if (this.IsLocked && !this.IsDirty) { this.IsLocked = false; this.SetPageExitCheck(false); } } } } 
    

运行版本2

现在运行该应用程序。点击一个编辑按钮。基础页面上的所有链接均被禁用。单击设置污点以模拟编辑字段。现在尝试关闭或导航或关闭浏览器。所有选项都应包括在内

  1. 关闭浏览器,在工具栏中导航,F5或关闭浏览器窗口,将在浏览器中显示您是否要离开对话框
  2. 关闭会为您提供脏退出选项。
  3. 单击浏览器窗口中的任何位置都不会执行任何操作。

Blazor Modal对话框编辑器

版本3

现在让我们继续创建可以在生产中使用的ModalDialog框架。这将是一个模态对话框包装,我们可以使用它来显示任何组件。在这种情况下,WeatherViewerModalEditor组成。我创建了一个Component目录结构来组织代码,但是为了简单起见,将它们全部保留在基本名称空间中。

首先,我们需要添加一些实用程序类。

ModalResultModalResultType

Components/ModalDialog中,添加一个ModalResult类。代码如下。

Dialog关闭时,该类为返回值提供了一个容器。它返回一个对象Data和一个ModalResultType。静态构造函数用于构建实例。

namespace CEC.Blazor.Editor { public enum ModalResultType { NoSet, OK, Cancel, Exit } public class ModalResult { public ModalResultType ResultType { get; private set; } = ModalResultType.NoSet; public object Data { get; set; } = null; public static ModalResult OK() => new ModalResult() { ResultType = ModalResultType.OK }; public static ModalResult Exit() => new ModalResult() { ResultType = ModalResultType.Exit }; public static ModalResult Cancel() => new ModalResult() { ResultType = ModalResultType.Cancel }; public static ModalResult OK(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.OK }; public static ModalResult Exit(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.Exit }; public static ModalResult Cancel(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.Cancel }; } }

ModalOptions

现在添加一个ModalOptions类。它是将配置选项传递到模式对话框的容器。这是带有gettersetter的简单IEnumerable集合对象。

using System.Collections; using System.Collections.Generic; namespace CEC.Blazor.Editor { public class ModalOptions :IEnumerable 
    
      > { // Ststic List of options - only one currently defined public static readonly string __Width = "Width"; private Dictionary 
     
       Parameters { get; } = new Dictionary 
      
        (); public IEnumerator 
       
         > GetEnumerator() { foreach (var item in Parameters) yield return item; } IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); public T Get 
        
          (string key) { if (this.Parameters.ContainsKey(key)) { if (this.Parameters[key] is T t) return t; } return default; } public bool TryGet 
         
           (string key, out T value) { value = default; if (this.Parameters.ContainsKey(key)) { if (this.Parameters[key] is T t) { value = t; return true; } } return false; } public bool Set(string key, object value) { if (this.Parameters.ContainsKey(key)) { this.Parameters[key] = value; return false; } this.Parameters.Add(key, value); return true; } } } 
          
         
        
       
      
    

IModal对话

添加IModalDialog接口。它定义了我们构建的任何模式对话框都需要实现的public属性和方法。它在我们的代码和特定的模态对话框实现之间提供了一个抽象层——干净的CSS版本,BootStrap版本

using Microsoft.AspNetCore.Components; using System.Threading.Tasks; namespace CEC.Blazor.Editor { public interface IModalDialog { public ModalOptions Options { get; } Task 
    
      ShowAsync 
     
       (ModalOptions options) where TModal : IComponent; void Dismiss(); void Close(ModalResult result); void Update(ModalOptions options = null); void Lock(bool setlock); } } 
      
    

模态对话框

现在,添加ModalDialogIModalDialog的基本CSS不可知实现。

Razor标记非常简单,类似于我们编写的原型:

  1. Display 将其关闭然后再打开。
  2. ModalDialog实例被级联,从而包裹部件具有穿过访问模态对话框的IModalDialog接口。
  3. 宽度可以通过ModalOptions设置。
  4. 内容在RenderFragment中构建,命名为_Content
@namespace CEC.Blazor.Editor @implements IModalDialog @if (this.Display) { 
     
      
     }

在代码中:

  1. 我们有一个通过ShowAsync传递的ModalOptions属性。
  2. 我们从ModalOptions得到Width
  3. 我们使用一个TaskCompletionSource对象来提供异步行为,而Task调用者可以await
  4. ShowAsync使用泛型。TModal可以是IComponentComponentBase实现的任何组件。
  5. ShowAsync_Content使用RenderTreeBuilder进行构建:将组件类型TModal的新实例添加到_Content中。然后将其Display设置为true并且模式对话框重新渲染。如果TModalWeatherEditor,则控件有效地以
    作为其内容。
  6. DismissClose通过设置Displayfalse并呈现控件来关闭模态对话框。他们还清除内容并设置Task调用者可能正在等待完成的内容。
  7. 其余代码是原型代码的修改版本。
using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using System.Threading.Tasks; namespace CEC.Blazor.Editor { public partial class ModalDialog : IModalDialog { [Inject] private IJSRuntime _js { get; set; } public ModalOptions Options { get; protected set; } = new ModalOptions(); public bool Display { get; protected set; } public bool IsLocked { get; protected set; } protected RenderFragment _Content { get; set; } protected string Width => this.Options.TryGet 
    
      (ModalOptions.__Width, out string value) ? $"width:{value}" : string.Empty; protected TaskCompletionSource 
     
       _ModalTask { get; set; } = new TaskCompletionSource 
      
        (); public Task 
       
         ShowAsync 
        
          (ModalOptions options) where TModal : IComponent { this.Options = options ??= this.Options; this._ModalTask = new TaskCompletionSource 
         
           (); this._Content = new RenderFragment(builder => { builder.OpenComponent(1, typeof(TModal)); builder.CloseComponent(); }); this.Display = true; InvokeAsync(StateHasChanged); return this._ModalTask.Task; } /// 
           /// Method to update the state of the display based on UIOptions ///  /// 
           public void Update(ModalOptions options = null) { this.Options = options ??= this.Options; InvokeAsync(StateHasChanged); } ///  /// Method called by the dismiss button to close the dialog /// sets the task to complete, show to false and renders the component /// (which hides it as show is false!) ///  public async void Dismiss() { _ = this._ModalTask.TrySetResult(ModalResult.Cancel()); this.Display = false; this._Content = null; await InvokeAsync(StateHasChanged); } ///  /// Method called by child components through the cascade value of this component /// sets the task to complete, show to false and renders the component /// (which hides it as show is false!) ///  ///  public async void Close(ModalResult result) { _ = this._ModalTask.TrySetResult(result); this.Display = false; this._Content = null; await InvokeAsync(StateHasChanged); } private void SetPageExitCheck(bool action) { _js.InvokeAsync 
            
              ("cecblazor_setEditorExitCheck", action); } public void Lock(bool setlock) { if (setlock && !this.IsLocked) { this.IsLocked = true; this.SetPageExitCheck(true); } else if (this.IsLocked && !setlock) { this.IsLocked = false; this.SetPageExitCheck(false); } } } } 
              
          
         
        
       
      
    

天气组件

我只在这里展示WeatherEditorWeatherViewer是没有功能的较简单版本。有关代码,请参见Repo

天气编辑器

Razor代码与原型模式对话框中的代码相同。

@namespace CEC.Blazor.Editor 
    

Weather Editor

Date
@DateTime.Now.ToLongDateString()
Temperature C
0 deg C
Temperature C
32 deg F
Summary
Another Beast-from-the-East day
@if (this.DoDirtyExit) { } else { }

许多控制代码也从原型代码中提取。我们选择级联IModalDialog以使用其public接口方法与ModalDialog包装器进行交互。例如, Exit检查控件是否IsDirty。如果很干净,它会调用this.Modal?.Close(ModalResult.OK()),以关闭对话框包装并销毁此类的实例。

using Microsoft.AspNetCore.Components; namespace CEC.Blazor.Editor { public partial class WeatherEditor : ComponentBase { [CascadingParameter] private IModalDialog Modal { get; set; } public bool IsDirty { get; set; } public bool IsLocked { get; private set; } private bool DoDirtyExit { get; set; } private string DirtyButtonCss => this.IsDirty ? "btn-warning" : "btn-info"; private string DirtyButtonText => this.IsDirty ? "Set Clean" : "Set Dirty"; private void Exit() { if (this.IsDirty) { this.DoDirtyExit = true; this.InvokeAsync(this.StateHasChanged); } else this.Modal?.Close(ModalResult.OK()); } public void DirtyExit() { if (this.DoDirtyExit) { this.IsDirty = false; this.Modal?.Lock(false); this.Modal?.Close(ModalResult.Cancel()); } } public void CancelExit() { this.DoDirtyExit = false; this.InvokeAsync(this.StateHasChanged); } public void SetDirty() { if (this.IsDirty) this.DoDirtyExit = false; this.IsDirty = !this.IsDirty; this.Modal?.Lock(this.IsDirty); this.InvokeAsync(this.StateHasChanged); } } }

FetchDataModal

最后,我们在Pages创建一个被称为FetchDataModalFetchData新版本。

Razor标记与原型非常相似。

  1. 我们正在使用ModalDialog模式对话框的版本。
  2. 现在,每行都有两个按钮以显示编辑器查看器
@page "/fetchdatamodal" @using CEC.Blazor.Editor.Data 

Weather forecast

This component demonstrates fetching data from a service.

@if (forecasts == null) {

Loading...

} else { @foreach (var forecast in forecasts) { }
Date Temp. (C) Temp. (F) Summary
@forecast.Date.ToShortDateString() @forecast.TemperatureC @forecast.TemperatureF @forecast.Summary
}

与原型非常相似,但:

  1. ShowViewDialog设置ModalOptions然后调用await this.Modal.ShowAsync

    (options)
    。我们正在运行的异步和完成之前等待的对话框打开,然后关闭,并传递一个类型WeatherViewerModaldialog以显示。
  2. ShowEditDialog如上操作,但加载WeatherViewer
using CEC.Blazor.Editor.Data; using Microsoft.AspNetCore.Components; using System; using System.Threading.Tasks; namespace CEC.Blazor.Editor.Pages { public partial class FetchDataModal : ComponentBase { [Inject] WeatherForecastService ForecastService { get; set; } private WeatherForecast[] forecasts; private ModalDialog Modal { get; set; } protected override async Task OnInitializedAsync() { forecasts = await ForecastService.GetForecastAsync(DateTime.Now); } private async void ShowViewDialog() { var options = new ModalOptions(); options.Set(ModalOptions.__Width, "60%"); await this.Modal.ShowAsync 
    
      (options); } private async void ShowEditDialog() { var options = new ModalOptions(); options.Set(ModalOptions.__Width, "80%"); await this.Modal.ShowAsync 
     
       (options); // any code to execute after the editor is complete goes here } } } 
      
    

总结

希望我已经展示了一些用于处理BlazorSPA中的编辑状态的技术和策略。本文的一些要点:

  1. 您可以从肮脏的表单中阻止用户拥有的所有正常退出路线。
  2. 您可以构建HTML对话框,其行为与桌面应用程序中的模式对话框相似。
  3. 模式对话框可以是异步的,您可以等待其完成。

https://www.codeproject.com/Articles//A-Blazor-Modal-Dialog-Editor

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215739.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午1:33
下一篇 2026年3月18日 下午1:33


相关推荐

  • idea打包docker镜像特别慢_把代码和环境做成docker镜像

    idea打包docker镜像特别慢_把代码和环境做成docker镜像1.安装docker插件在plugins中搜索docker安装,完成后重启。

    2022年10月3日
    4
  • 主机网址怎么查_主机名查询

    主机网址怎么查_主机名查询由于JEO.VEE在做国外空间主机评测服务,平时会有很多朋友询问主机方面的问题,最常见的就是“哪个国外主机商最好?”或者“justhost主机服务怎么样?”等等很多类似的问题。其实国外大部分主机都还是可以的,没有哪个主机商好,也没有哪个最差劲。只有是不适合你。到底怎么知道哪个主机商是否适合自己的站点呢?你可以与你网站规模相类似的站点做下比较。看看对方网站在那个服务器,使用的哪个空间商。比如你的

    2022年10月9日
    3
  • 8款安卓数据恢复软件测评 2019更新版【国外篇】

    8款安卓数据恢复软件测评【国外篇】相信多数人都有过手机数据丢失的悲痛经历吧,尤其是当你没有任何可用的备份的时候。前几天我也遇到了这个问题,那个着急和纠心啊,于是我就开始了全网搜索国内外一切可用的手机数据恢复软件。我把网上能找的能试用的都给试了一遍,这里给大家总结一下!和手机系统一样,现在的手机数据恢复软件也区分为安卓,iOS和WP等,目前市场上主流的是针对安…

    2022年4月9日
    152
  • LINUX环境tomcat宕机自启

    LINUX环境tomcat宕机自启写一个monitor.sh脚本用于判断tomcat进程是否存在,若不存在则启动tomcat脚本链接https://download.csdn.net/download/qq_41959871/13722321查看定时任务状态systemctlstatuscrond/sbin/servicecrondstart//启动服务/sbin/servicecrondstop//关闭服务/sbin/servicecrondrestart//重启服务/sbin/servicecron

    2022年7月26日
    10
  • xshell怎么退出vi_xshell5

    xshell怎么退出vi_xshell5最近在学习Linux时,初次使用Vi编辑模式编辑文本,但是编辑完成之后,不知道怎么退出编辑模式,然后在网上查找了一番,特此分享给各位老铁:下面总结一些vi退出命令,学习!进入编辑模式,按o进行编辑编辑结束,按ESC键跳到命令模式,然后输入退出命令::w 保存文件但不退出vi编辑:w! 强制保存,不退出vi编辑:wfile 将修改另存到file中,不退出vi…

    2022年9月30日
    4
  • centos8安装pycharm_pycharm激活教程

    centos8安装pycharm_pycharm激活教程Linuxcentos7下pycharm的安装教程Pycharm是一个十分优秀的PythonIDE,Windows下的软件都一个德行,傻瓜式下一步安装,除了一些大型软件,在Windows下有一个不好,Python编译器等等这些Python环境需要自己安装,Linux下天然支持Python,因为内核已经集成了Python2.7,如果需要更换Python3也可以很快的就安装上(相比c语言,要友好太多了,gcc由于与内…

    2022年8月28日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号