ABP+Angular框架搭建踩坑记
<p>最近用angular和.net core 搭建一个前后端分离的BS框架,准备使用ABP模板实现。</p><p>1、首先在ABP的官网https://aspnetboilerplate.com/Templates去创建一个框架代码,如下</p>
<p><img src="https://img2020.cnblogs.com/blog/1715230/202101/1715230-20210106145935759-32541022.png"></p>
<p> </p>
<p> </p>
<p> 因为准备前端代码也在VS2019里面写,所以此处勾上了One solution ...即前后端都放在一个解决方案里面。</p>
<p>2、创建后解压下载下来的安装包,打开刚才填的项目名的解决方案。如果数据库也在本机,则使用windows验证登录数据库创建一个按appsettings.json里面的数据库连接字符串中的数据库名在本机创建一个相应的数据库。后期要部署再其他数据库可以重新配置数据库连接字符串,用EF重新迁移数据库,用MySQL或者其他数据库需要安装相应EF 相关的数据库组件当然可能也会踩坑,此处不延申了。</p>
<p><img src="https://img2020.cnblogs.com/blog/1715230/202101/1715230-20210106150506256-206423857.png"></p>
<p> </p>
<p> </p>
<p> </p>
<p>3、用VS运行OPS02.Migrator迁移数据库,也可以用EF命令行 update-database迁移数据库(用命令行的时候注意选中 XXX.Migrator项目)</p>
<p><img src="https://img2020.cnblogs.com/blog/1715230/202101/1715230-20210106151350030-626864088.png"></p>
<p> </p>
<p> </p>
<p> 4、运行XXX.Web.Host项目,后端项目就跑起来了,可以在http://localhost:21021/swagger/index.html看到后端的一些webapi。</p>
<p> </p>
<p>5、cmd命令行工具里面用cd命令进入XXX.Web.Host目录,运行npm install 命令(前提需要安装好node.js),运行此命令由于angular cli版本问题可能会出错,报错卸载angular重装,在搜到的卸载重装的命令执行了很多遍,我这边还是报错,看了一下项目 主要就是@angular-devkit/build-angular包没有安装上,单独执行npm install -save-dev @angular-devkit/build-angular安装还是报错,在卸载重装的时候需要清理angular安装cache,看cmd的报错猜想可能是angular-devkit/build-angular没清理干净,于是到 用户名\AppData\Roaming\npm\node_modules目录下面手动删掉angular-devkit/build-angular,再执行便npm install -save-dev @angular-devkit/build-angular安装成功了。然后执行npm start 访问http://localhost:4200 地址即可看到登录页面(执行npm start前需确保后端在运行中,否则前端项目启动时访问后端接口出错会加载不出页面)。输入用户名admin密码123qwe即可登录</p>
<p><img src="https://img2020.cnblogs.com/blog/1715230/202101/1715230-20210106153902222-1911486018.png"><img src="https://img2020.cnblogs.com/blog/1715230/202101/1715230-20210106154023600-486602147.png"></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> 5.前后端都在VS2019里面写在VS里面能同时启动运行前后端项目,可以修改XXX.Web.Host中的Startup.cs配置AspNetCore.SpaServices.AngularCli,在Startup.cs的IServiceProvider ConfigureServices(IServiceCollection services)方法中添加</p>
<p> services.AddSpaStaticFiles(configuration =><br> {<br> configuration.RootPath = "./dist";<br> });</p>
<p>定义Spa静态文件根目录,</p>
<p>然后在Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)方法中配置使用Spa静态文件服务</p>
<p>app.UseStaticFiles();</p>
<p>最后配置使用Spa网页</p>
<p>app.UseSpa(spa =><br> {</p>
<p> spa.Options.SourcePath = "./";</p>
<p> if (true)<br> {<br> spa.UseAngularCliServer(npmScript: "start");<br> }<br> });</p>
<p>配置完之后的Startup.cs如下,配置好之后即可以在VS启动XXX.Web.Host项目同时启动angular前端和ABP.net core 后端</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.IO;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Linq;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Reflection;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.Builder;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.Hosting;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.Configuration;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.DependencyInjection;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.Logging;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Castle.Facilities.Logging;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.AspNetCore;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.AspNetCore.Mvc.Antiforgery;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.Castle.Logging.Log4Net;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.Extensions;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> OPS02.Configuration;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> OPS02.Identity;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.AspNetCore.SignalR.Hubs;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.Dependency;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Abp.Json;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.OpenApi.Models;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Newtonsoft.Json.Serialization;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.SpaServices.AngularCli;
</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> OPS02.Web.Host.Startup
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Startup
{
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">string</span> _defaultCorsPolicyName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">localhost</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">string</span> _apiVersion = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">v1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span><span style="color: rgba(0, 0, 0, 1)"> IConfigurationRoot _appConfiguration;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Startup(IWebHostEnvironment env)
{
_appConfiguration </span>=<span style="color: rgba(0, 0, 0, 1)"> env.GetAppConfiguration();
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> IServiceProvider ConfigureServices(IServiceCollection services)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">MVC</span>
<span style="color: rgba(0, 0, 0, 1)"> services.AddControllersWithViews(
options </span>=><span style="color: rgba(0, 0, 0, 1)">
{
options.Filters.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> AbpAutoValidateAntiforgeryTokenAttribute());
}
).AddNewtonsoftJson(options </span>=><span style="color: rgba(0, 0, 0, 1)">
{
options.SerializerSettings.ContractResolver </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> AbpMvcContractResolver(IocManager.Instance)
{
NamingStrategy </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> CamelCaseNamingStrategy()
};
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Configure CORS for angular2 UI</span>
<span style="color: rgba(0, 0, 0, 1)"> services.AddCors(
options </span>=><span style="color: rgba(0, 0, 0, 1)"> options.AddPolicy(
_defaultCorsPolicyName,
builder </span>=><span style="color: rgba(0, 0, 0, 1)"> builder
.WithOrigins(
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> App:CorsOrigins in appsettings.json can contain more than one address separated by comma.</span>
_appConfiguration[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">App:CorsOrigins</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">]
.Split(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, StringSplitOptions.RemoveEmptyEntries)
.Select(o </span>=> o.RemovePostFix(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Swagger - Enable this line and the related lines in Configure method to enable swagger UI</span>
services.AddSwaggerGen(options =><span style="color: rgba(0, 0, 0, 1)">
{
options.SwaggerDoc(_apiVersion, </span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OpenApiInfo
{
Version </span>=<span style="color: rgba(0, 0, 0, 1)"> _apiVersion,
Title </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OPS02 API</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Description </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OPS02</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> uncomment if needed TermsOfService = new Uri("</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://example.com/terms</span><span style="color: rgba(0, 128, 0, 1)">"),</span>
Contact = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OpenApiContact
{
Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OPS02</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Email </span>= <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty,
Url </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Uri(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://twitter.com/aspboilerplate</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">),
},
License </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OpenApiLicense
{
Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MIT License</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Url </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Uri(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/LICENSE</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">),
}
});
options.DocInclusionPredicate((docName, description) </span>=> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Define the BearerAuth scheme that's in use</span>
options.AddSecurityDefinition(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bearerAuth</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OpenApiSecurityScheme()
{
Description </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Authorization</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
In </span>=<span style="color: rgba(0, 0, 0, 1)"> ParameterLocation.Header,
Type </span>=<span style="color: rgba(0, 0, 0, 1)"> SecuritySchemeType.ApiKey
});
});
services.AddSpaStaticFiles(configuration </span>=><span style="color: rgba(0, 0, 0, 1)">
{
configuration.RootPath </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">./dist</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
});
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Configure Abp and Dependency Injection</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> services.AddAbp<OPS02WebHostModule><span style="color: rgba(0, 0, 0, 1)">(
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Configure Log4Net logging</span>
options => options.IocManager.IocContainer.AddFacility<LoggingFacility><span style="color: rgba(0, 0, 0, 1)">(
f </span>=> f.UseAbpLog4Net().WithConfig(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">log4net.config</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
)
);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseAbp(options </span>=> { options.UseAbpRequestLocalization = <span style="color: rgba(0, 0, 255, 1)">false</span>; }); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Initializes ABP framework.</span>
<span style="color: rgba(0, 0, 0, 1)">
app.UseCors(_defaultCorsPolicyName); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Enable CORS!</span>
<span style="color: rgba(0, 0, 0, 1)">
app.Use(</span><span style="color: rgba(0, 0, 255, 1)">async</span> (context, next) => { <span style="color: rgba(0, 0, 255, 1)">await</span> next(); <span style="color: rgba(0, 0, 255, 1)">if</span> (context.Response.StatusCode == <span style="color: rgba(128, 0, 128, 1)">404</span> && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/api/services</span><span style="color: rgba(128, 0, 0, 1)">"</span>, StringComparison.InvariantCultureIgnoreCase)) { context.Request.Path = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/index.html</span><span style="color: rgba(128, 0, 0, 1)">"</span>; <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> next(); } });
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpRequestLocalization();
app.UseEndpoints(endpoints </span>=><span style="color: rgba(0, 0, 0, 1)">
{
endpoints.MapHub</span><AbpCommonHub>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/signalr</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
endpoints.MapControllerRoute(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{controller=Home}/{action=Index}/{id?}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
endpoints.MapControllerRoute(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">defaultWithArea</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{area}/{controller=Home}/{action=Index}/{id?}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
});
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Enable middleware to serve generated Swagger as a JSON endpoint</span>
app.UseSwagger(c => { c.RouteTemplate = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">swagger/{documentName}/swagger.json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; });
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)</span>
app.UseSwaggerUI(options =><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> specifying the Swagger JSON endpoint.</span>
options.SwaggerEndpoint($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/swagger/{_apiVersion}/swagger.json</span><span style="color: rgba(128, 0, 0, 1)">"</span>, $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OPS02 API {_apiVersion}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
options.IndexStream </span>= () =><span style="color: rgba(0, 0, 0, 1)"> Assembly.GetExecutingAssembly()
.GetManifestResourceStream(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OPS02.Web.Host.wwwroot.swagger.ui.index.html</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
options.DisplayRequestDuration(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Controls the display of the request duration (in milliseconds) for "Try it out" requests.</span>
}); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> URL: /swagger</span>
<span style="color: rgba(0, 0, 0, 1)">
app.UseSpa(spa </span>=><span style="color: rgba(0, 0, 0, 1)">
{
spa.Options.SourcePath </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">./</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">)
{
spa.UseAngularCliServer(npmScript: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">start</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
});
}
}
}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/CodeTreker/p/14241580.html
頁:
[1]