GVKun编程网logo

使用dva+antd快速构建单页面应用(antd dva)

11

最近很多小伙伴都在问使用dva+antd快速构建单页面应用和antddva这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展angularjs–寻找有关如何构建单个页面应用程序的说明

最近很多小伙伴都在问使用dva+antd快速构建单页面应用antd dva这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展angularjs – 寻找有关如何构建单个页面应用程序的说明、asp.net-mvc – 如何使用ASP.NET MVC和表单身份验证创建单页面应用程序(SPA)?、Flask + Vue.js:快速实现单页面应用、React单页面应用使用antd的锚点跳转失效等相关知识,下面开始了哦!

本文目录一览:

使用dva+antd快速构建单页面应用(antd dva)

使用dva+antd快速构建单页面应用(antd dva)

项目结构及使用工具集

原文地址: 个人博客或joescott.coding.me/blog

`project
   |----- src    项目源代码
   |----- dist   项目编译目标
   |----- .roadhogrc 路霸运行配置文件
   |----- lumen_api RESTful api代码目录
   |----- mock   模拟数据服务目录


`src
  |---  index.js      入口js文件
  |---  index.html    项目入口html文件
  |---  router.js     路由文件
  |---  routes        子路由目录, 下面每个子路由使用一个单独的文件夹
  |---  components    组件目录,这里特指公共组件
  |---  models        model目录
  |---  services      服务目录
  |---  utils         工具包目录
  |---  constants.js  常量文件,这个文件其实可放入utils目录,然后统一暴露出去

以上是项目中的总体目录结构。 下面详细介绍几个重要部分的结构。

此应用是当入口应用,入口在src/index.js, 配置在.roadhogrc中,当然roadhog还支持多入口模式,这里不涉及。

组件系统

项目中组件分为两大类,容器组件和呈现组件。

容器组件

容器组件对应于每个独立的route页面。每个容器组件都维护一个相关的state,所有的state改变都由容器最终执行。容器组件负责向其子组件(呈现组件)分配属性(props)。

该项目中,所有子组件仅作呈现组件,没有state,只有从父级组件传递下来的props。state由容器组件统一管理,然后分发到子组件中。

容器组件在该项目中以路由组件的形式存在,存放在src/routes下面对应的子目录中。每个容器组件使用的子组件(非共享的)都在路由组件目录中存放。而使用到的公共组件则存放在components目录下面。例如公共组件提供数据表的包装,下拉操作控件包装等等,在多个容器组件的子组件中会用到。都被抽离到components目录中。

容器组件的范本如下:

// routes/users/index.js
import React,{ PropTypes } from 'react'
import { RouterRedux } from 'dva/router'
import { connect } from 'dva'
function Users({ location,dispatch,users,loading }) {
}
Users.propTypes = {
  menus: PropTypes.object,// ...
}
function mapStatetoProps(state) {
  return {
    users: state.users,loading: state.loading.models.users,}
}
export default connect(mapStatetoProps)(Users)

创建一个类Users,接收一些参数,用于类自己使用,后面会通过connect将state联系给这些参数。
设置类的propTypes,编译的时候会对属性进行检查,发现类型错误,编译失败。确保项目质量。

将state和类的属性联系起来, 通过connect方法来实现导出组件

呈现组件

项目中的呈现组件根据共享特性,分别存放于routers目录和components目录中。它们是无state组件,只从父组件获取到props。比如容器组件向呈现组件传入state相关的部分属性和相应的操作方法给呈现组件的props,一级级递归传下去。 而子组件的交互产生改变state的操作,则由子组件沿原路上传回给容器组件,最终由容器组件的具体方法来触发state的同步,以及UI的更新。

呈现组件的范本如下:

import React,{ PropTypes } from 'react'
// ...
function XView ({
  prop1,prop2,prop3,// ...
}) => {
  // create XView propOpts
  const propOpts = {
    p1,p2,// ...
  }
  return (
    <div {...propOpts}>
     <div>something to render</div>
    </div>
  )
}
XView.propTypes = {
  // ...
}
export default XView

呈现组件和容器组件相比,就是没有使用connect进行state到prop建立联系。这很正常,因为呈现组件是无状态的的,它只有属性,从父层传下来的属性而已。

有了这样的呈现组件,那么就可以直接在父层调用:

<XView {...props}>
</XView>

XView调用的时候,属性props会作为XView类构造函数的输入。

模型系统

该应用的模型model按业务维度设计。模型设计有两种实现方式:

  • 按数据维度设计: 抽离数据和相关操作的方法。 只关心数据本身,至于使用数据模型的组件所遇到的状态管理则与模型无关,而是作为组件自身的state来维护。

  • 按照业务维度设计: 将数据和使用数据强关联组件中的状态抽象成model的方法。

该应用使用后者。

模型位于src/models,每个独立的route都对应一个model,每个model包含如下属性:

  • namespace: 模型的命名空间,这个是必须的,而且在同一个应用中每个模型的该属性是唯一的。使用可读性较强的词语作namespace,比如users,categories,menus之类的。

  • state: 与具体route相关的所有状态数据结构存放在该属性中。比如数据列表,当前操作项,弹出层的显隐状态等等都可以保存在该属性中。

  • subscriptions: 该属性是dva的8个核心概念之一。 该属性存放从源获取数据的设置。 比如当pathname和给定的名称匹配的时候,执行什么操作之类的设置。

  • effects: 该属性存放的是异步操作的一些方法。从词语字面意思理解来说,是副作用,就是请求非幂等性的。比如异步获取数据列表、异步更新、异步插入、异步删除等等操作。

  • reducers: 该属性存放的是对state的合并方法。基本上就是将新的state值合并到原来的state中,以达到state的同步。reducer的含义就是多个合并返回一个的意思。

除了上面的几个属性外,需要另外注意几个方法的使用:

  • select: 从state中查找所需的子state属性。该方法参数为state,返回一个子state对象。

  • put: 创建一条effect信息,指示middleware发起一个action到Store. put({type: ‘xxxx’,payload: {}})

  • call: 创建一条effect信息,指示middleware使用args作为fn的参数执行,例如call(services.create,payload)

基本的model范本如下:

// models/users.js
export default {
  namespace: 'users',state: {},subscriptions: {},effects: {},reducers: {}
}

服务(services)

有了上面的两个部分,基本的静态交互已经就绪,就剩下和真正的或模拟的API交互了,这部分抽离为services,即services提供异步数据获取。
每个services对应一个route的操作集合,比如query查询列表,update更新记录,create新增记录,delete删除记录。

这个层面的设计,相对比较简单,直接在utils中包装一个request类,提供fetch或ajax功能,然后services中直接将请求参数传入相应方法即可。返回请求的结果Promise。

mock服务

roadhog使用json作为运行时配置,它提供了代理的配置,简单配置如下:

"proxy": {
    "/api": {
      "target": "http://localhost:3004/",//      "target": "http://192.168.200.30:8099/api","changeOrigin": true,"pathRewrite": { "^/api" : "" }
    }
  }

比如使用json-server+mockjs实现的mock服务,启动端口号为3004, 那么使用target指向3004端口,那么请求/api/xxx的时候就进入json-server提供的mock服务。

另外如果和api服务连调的话,同样可以将target指向真实api服务的base url。 例如上面注释掉的那行。

而在正式打包上线后,就不走proxy,免配置修改,直接生效。

API设计

API采用lumen微框架实现的restful api,这块的不作过多介绍,如有兴趣自行搜索lumen官网查看,或参照lumen_api中的代码来查看。

总结

整个设计下来, 开发流畅性非常不错。 开发体验也非常好。 暂时该项目不支持less,对图片的处理也稍逊色,后续待解决。

roadhog源码分析

roadhog是对webpack功能作的一个封装,roadhog会读取自己的配置信息,然后转换为webpack的配置对象,最终调用webpack作项目打包。下面对roadhog源码作简单分析。

roadhog提供了三个命令:

  • roadhog build: 构建production bundle

  • roadhog server: 启动开发环境

  • roadhog test: 启动测试

result = spawn.sync(
  'node',[require.resolve(`../lib/${script}`)].concat(args),{ stdio: 'inherit' }
);
process.exit(result.status);

上面代码中的script的值为build,server或test,而args是roadhog命令后面的option选项。

Options:
  --debug            Build without compress           [boolean] [default: false]
  --watch,-w        Watch file changes and rebuild   [boolean] [default: false]
  --output-path,-o  Specify output path                [string] [default: null]
  --analyze          Visualize and analyze your Webpack bundle.
                                                      [boolean] [default: false]
  -h                 Show help                                         [boolean]

roadhog源码中还有一个异步post上报功能, 上报给阿里你当前的平台信息,git用户信息等。 不知道这个具体用于干啥的。 ^-^。
roadhog xxx实际上是调用lib/xxx.js执行具体任务。

我们下面先看看build.js的逻辑。

roadhog build

build.js代码骨架如下:

var _extends = Object.assign || function (target) {
  // Object.assign polyfill
}
exports.build = build;
process.env.NODE_ENV = 'production';
var argv = require('yargs').usage()
  .option()
  .option()
// ...
function build(argv) {
  // the body of the build
}
if (require.main === module) {
  build(_extends({},argv,{ cwd: process.cwd() }));
}

注意这里require.main === module判断模块是否为应用的主模块,类似于python的if name == “__main__“。

也就是说roadhog build实际上就是调用了build.js暴露出去的build方法。

argv分析

  • debug: 布尔类型值,表示是否使用压缩模式构建

  • watch: 短选项名w,表示观察文件的改动,然后重新构建

  • output-path: 别名o,表示构建的目标地址, 默认为./dist目录。

  • analyze: 可视化并分析你的webpack打包

  • h: 显示帮助信息

build函数分析

path(lib/config/path.js)

该文件根据build.js当前工作目录,获取应用程序几个重要的相关文件或文件夹的绝对路径:

  • appBuild: dist目录的绝对路径

  • appPublic: public目录的绝对路径

  • appPackageJson: package.json文件的绝对路径

  • appSrc: src源代码目录的绝对路径

  • appNodeModules: node_modules目录的绝对路径

  • ownNodeModules: roadhog自身的node_modules的绝对路径

  • resolveApp: 该函数接收一个相对路径,返回该目录相对应用程序目录的绝对路径

  • appDirectory: 应用程序所在目录的绝对路径

  • getConfig(lib/utils/getConfig.js)

该方法根据环境获取应用程序当前目录下面的真实配置文件的内容:realGetConfig(‘.roadhogrc’,env,pkg,paths)。

默认使用.roadhogrc配置文件,env为当前环境模式,pkg为package.json文件内容,paths是上面的path相关的路径信息。

roadhog默认配置文件使用json格式的配置,允许在文件中使用注释:

return (0,_parseJsonPretty2.default)((0,_stripJsonComments2.default)((0,_fs.readFileSync)(rcConfig,'utf-8')),'./roadhogrc');

另外如果不使用.roadhogrc这种配置文件,还可以使用.roadhogrc.js文件,使用纯js来实现配置。返回一个配置对象就可以了。

使用.js配置文件可以允许在配置中使用js变量和方法。灵活度还是蛮高的。

如果两者都没有,roadhog依然可以正常使用,自定义配置对象为空对象而已。

另外配置文件中可以使用package.json中的包名称(name)和版本信息(version)。 分别使用$npm_package_name变量和$npm_package_version变量。

另外如果是test环境模式,可以注册babel。这块通过lib/utils/registerBabel.js代码中实现的:

require('babel-register')({
  only: ...
  presets: ...
  plugins: ...
  babelrc: ...
})

roadhog配置转webpack配置

在获取了roadhog配置之后,就会将roadhog的配置转换成webpack的配置对象,毕竟底层使用的是webpack来打包的。
roadhog将命令选项(argv),应用构建目录(appBuild),自有配置(.roadhogrc内容)和应用程序的路径信息合并到默认的webpack.config.prod.js中。

webpack.config.prod.js返回一个函数,该函数返回合并后的webpack对象。

// lib/config/webpack.config.prod.js
export default function(args,appBuild,config,paths) {
  return {
    bail: true,entry: xxxx
    // ...
  }
}

roadhog除了提供默认的webpack配置,还支持用户自定义webpack配置覆盖roadhog默认配置, 在项目根目录下面建立webpack.config.js文件,该文件的模版如下:

export default function (config,env) {
  const newConfig = {};
  // merge or override
  return newConfig;
}

接收的config为roadhog合并默认配置后的配置对象, env是环境模式。

也就是说完全可以利用所有webpack的功能来实现。

构建过程

在构建之前,先递归读取构建目录中之前所有的.js文件和.css文件,记录原始文件尺寸,并清理原来的构建目录中的文件。 然后将这些尺寸信息传入构建过程,进行真实构建。

realBuild

真实构建函数实现非常简单,代码如下:

function realBuild(prevIoUsSizeMap,resolve,argv) {
  if (argv.debug) {
    console.log('不压缩的方式构建');
  } else {
    console.log('优化的方式构建');
  }
  var compiler = (0,_webpack2.default)(config);
  var done = doneHandler.bind(null,prevIoUsSizeMap,resolve);
  if (argv.watch) {
    compiler.watch(200,done);
  } else {
    compiler.run(done);
  }
}

到目前为止,roadhog的打包构建功能已经完全解读完了。归根结底就是webpack打包。

参考连接

  • 项目代码

  • 组件设计方法

  • Redux-saga中文文档

  • ES6开发中的兼容性考虑

angularjs – 寻找有关如何构建单个页面应用程序的说明

angularjs – 寻找有关如何构建单个页面应用程序的说明

我们是一个开发人员团队,他们已经做了几年的Web应用程序编程.我们现在开始使用一个新项目,我们的目标是使它成为单页面应用程序.对于前端,我们使用角度.我们对angular比较熟悉,我们知道如何创建服务,指令,控制器等.我们知道如何使用内置服务,如$http和$resource以及如何使用路由(或使用 ui-router的状态),但我们仍然处于如何构建应用程序的早期状态.

我们很难找到解决这个一般问题的好资源(博客,视频,书籍).许多帖子都有一个非常简单的方法,如:

“要建立一个SPA你需要使用$http,这就是你如何做到的,不是很容易吗?”

他们可以非常好地理解每个组件的基础知识,但他们并没有解释将所有组件结合在一起的问题.我们遇到的问题有以下几种:

>我们是否构建了一个中央js对象来表示应用程序状态?如果应用程序是网上商店的后端,则中心对象可能是具有产品列表的公司,每个产品具有订单列表,并且每个产品都具有对客户的引用.或者我们是否将应用程序状态的表示拆分为不同的对象?如果是这样,我们如何让它们保持同步?
>要显示编辑实体的表单,我们创建一个将部分加载到视图中的路径,并使用要编辑的实体填充范围.我们从后端获取实体吗?或者如果我们已经在js模型中使用它,我们是否只是从那里获取它以便我们不需要发出http请求?

还有很多不清楚的地方,我意识到任何问题都不会有简单的答案,而是可能是不同的设计模式,有利有弊.我不希望我的所有问题的答案都作为对这篇文章的回应,而是我想找到一些资源(比如我说的博客,书)在应用程序级别上讨论这些问题.有些问题是特定于角度的,有些问题在单页应用程序中更为通用.有这样的资源吗?

解决方法

我自己对AngularJS比较陌生,我同意很难找到超越基础知识的信息.到目前为止,我发现的最有用的教程来自Dan Wahlin.

> http://weblogs.asp.net/dwahlin/archive/2013/04/12/video-tutorial-angularjs-fundamentals-in-60-ish-minutes.aspx
> http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx
> http://blogs.interfacett.com/getting-started-with-angularjs-video-series

这个60分钟的教程很棒,而且他的其他东西对于让你超越Hello World阶段很有帮助.我还观看了Angular的创作者Misko Hevery的几个演讲,他也非常好.

asp.net-mvc – 如何使用ASP.NET MVC和表单身份验证创建单页面应用程序(SPA)?

asp.net-mvc – 如何使用ASP.NET MVC和表单身份验证创建单页面应用程序(SPA)?

我正在使用Knockout将视图模式与外部模板和sammy用于路由,使用Web API从服务器获取数据.

问题是

>我如何使用服务器路由将用户重定向到客户端路由
例如#/ people / username的人/用户名.
>在验证用户时还有很大的困惑吗?
>如何在单页面应用程序中验证用户?
>有些页面无需登录即可查看?怎么实现呢?

我可以使用来自Controller的部分视图结果并在视图上获取吗?

解决方法

> Custom Routing,但要注意的是,如果你不得不这样做,从客户端获取数据会让人感到困惑.
>应该是您习惯的相同类型的身份验证. [Authorize]属性一如既往.
>应用程序将在启动时进行授权,“单页”部分不会影响该部分,除非您必须小心检查用户在 every AJAX request上的权限.
> authorize attribute可以放在类(控制器)级别以及方法(操作)级别,因此您可以根据需要选择它.
> Partial View Results and AJAX可能令人困惑.基本上,如果要使其正常工作,您将在正常条件下构建AJAX请求服务器端.

最后,你可能会试图这样做.微软的ASP.NET是一种非常厚的网络技术.我非常了解它,但我仍然会告诉你,我可以在许多其他技术中更快地构建单页应用程序.除此之外,根据您提出的问题类型,我得到的印象是您对ASP.NET很新,这对您来说将是一项重大挑战.

祝好运.阅读this book.这是较旧的技术,但我从来没有找到一本更好的教学良好实践的书.史蒂夫桑德森是个天才.

Flask + Vue.js:快速实现单页面应用

Flask + Vue.js:快速实现单页面应用

随着移动互联网和 web 技术的迅速发展,越来越多的应用需要提供流畅、快速的用户体验。传统的多页面应用已经无法满足这些需求,而单页面应用(spa)则成为了解决方案之一。

那么,如何快速实现单页面应用呢?本文将介绍如何利用 Flask 和 Vue.js 来构建 SPA。

Flask 是一个使用 Python 语言编写的轻量级 Web 应用框架,它的优点是灵活、易扩展、易于学习。Vue.js 是一个流行的 JavaScript 框架,它可以轻松地构建交互式的用户界面。

步骤一:创建 Flask 应用

首先,需要创建一个 Flask 应用,可以使用如下代码:

立即学习“前端免费学习笔记(深入)”;

from flask import Flask

app = Flask(__name__)

@app.route(''/'')
def index():
    return ''Hello world''

if __name__ == ''__main__'':
    app.run(debug=True)
登录后复制

上述代码创建了一个简单的 Flask 应用,当用户访问根目录时,会显示一个字符串“Hello world”。

步骤二:添加静态文件

接下来,需要添加一个静态文件夹,这个文件夹用于存放 Vue.js 和其他静态文件。在 Flask 应用中,可以使用如下代码将静态文件夹添加进来:

from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route(''/'')
def index():
    return send_from_directory(''static'', ''index.html'')

if __name__ == ''__main__'':
    app.run(debug=True)
登录后复制

上述代码中,send_from_directory 函数会从 static 文件夹中找到 index.html 文件并返回给用户。

步骤三:编写 Vue.js 代码

现在可以开始编写 Vue.js 代码了。Vue.js 通常需要使用 Webpack 进行打包,但在本文中仅使用 Vue.js 自带的 vue.js 和 vue-router.js 文件来简化流程。

首先,需要在 static 文件夹下创建一个 js 文件夹,并在里面添加 vue.js 和 vue-router.js 文件。然后,在 static 文件夹下创建一个 app.js 文件,并添加如下代码:

Vue.use(VueRouter);

const routes = [
  { path: ''/'', component: Home },
  { path: ''/about'', component: About },
  { path: ''*'', component: NotFound }
];

const router = new VueRouter({
    mode: ''history'',
    routes: routes
});

const app = new Vue({
    router,
    el: ''#app''
});
登录后复制

上述代码主要是配置 Vue Router,定义了三个路由:/ 对应 Home 组件、/about 对应 About 组件,* 对应 NotFound 组件。Home 和 About 组件可以在 app.js 文件中定义:

const Home = {
    template: `
        <div>
            <h1>Home</h1>
            <p>This is home page.</p>
        </div>
    `
};

const About = {
    template: `
        <div>
            <h1>About</h1>
            <p>This is about page.</p>
        </div>
    `
};

const NotFound = {
    template: `
        <div>
            <h1>404 Not Found</h1>
            <p>The page you''re looking for is not found.</p>
        </div>
    `
};
登录后复制

步骤四:将 Vue.js 和 Flask 应用连接起来

现在,Vue.js 和 Flask 应用都已经准备好了,需要将它们连接起来。在 index.html 中,添加如下代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Flask + Vue.js</title>
    <script src="js/vue.js"></script>
    <script src="js/vue-router.js"></script>
</head>
<body>
    <div id="app">
        <router-view></router-view>
    </div>
    <script type="text/javascript" src="{{ url_for(''static'', filename=''js/app.js'') }}"></script>
</body>
</html>
登录后复制

上述代码中, 会根据 Vue Router 的配置动态地显示对应的组件。url_for 函数将 Flask 应用生成的静态文件路径传递给 Vue.js。

最后,在 Flask 应用中添加如下代码:

from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route(''/'')
def index():
    return send_from_directory(''static'', ''index.html'')

@app.route(''/<path:path>'')
def any_path(path):
    return send_from_directory(''static'', ''index.html'')

if __name__ == ''__main__'':
    app.run(debug=True)
登录后复制

上述代码中,any_path 函数会将所有路由重定向到 index.html , 防止 Vue Router 访问错误页面。

现在,单页面应用就完成了!可以通过 Flask 启动应用,在浏览器中访问路由,测试应用的各个页面和交互效果了。

总结

本文介绍了如何使用 Flask 和 Vue.js 实现单页面应用。通过使用 Flask 提供接口和 Vue.js 渲染页面,可以快速地创建一个现代化的 Web 应用程序。

建议读者自行深入了解 Vue.js 和 Flask 的用法,并尝试用其他工具和框架实现类似的 SPA。

以上就是Flask + Vue.js:快速实现单页面应用的详细内容,更多请关注php中文网其它相关文章!

React单页面应用使用antd的锚点跳转失效

React单页面应用使用antd的锚点跳转失效

首先在react项目中引用antd的锚点

import {Anchor} from ''antd'';
const { Link } = Anchor;
<Anchor>
<Link href="#components-anchor-demo-basic" title="Basic demo" />
<Link href="#components-anchor-demo-static" title="Static demo" />
<Link href="#API" title="API">
<Link href="#Anchor-Props" title="Anchor Props" />
<Link href="#Link-Props" title="Link Props" />
</Link>
</Anchor>
//测试
<div id="components-anchor-demo-basic" style={{marginTop:"1000px"}}>
dddd
</div>
<div id="components-anchor-demo-static" style={{marginTop:"2000px"}}>
ffff
</div>

发现页面进行跳转而不是点位到页面的锚点,发现url有所改变
解决办法:加上location.hash可以解决
<Anchor>
<Link href={location.hash+"#components-anchor-demo-basic"} title="Basic demo" />
<Link href={location.hash+"#components-anchor-demo-static"} title="Static demo" />
<Link href="#API" title="API">
<Link href="#Anchor-Props" title="Anchor Props" />
<Link href="#Link-Props" title="Link Props" />
</Link>
</Anchor>


React不引入antd如何实现锚点跳转
代码如下:
scrollToAnchor (id){
document.getElementById(id).scrollIntoView(false);
}
render:
<div className="anchorLink">
<div className="navLink">
<ul>
<li>
<a href="javascript:;" onClick={()=>this.scrollToAnchor(''Summarize'')}>Summarize</a>
</li>
<li>
<a href="javascript:;" onClick={()=>this.scrollToAnchor(''ProductFunction'')}>ProductFunction</a>
</li>
<li>
<a href="javascript:;" onClick={()=>this.scrollToAnchor(''ToHelpAnswer'')}>ToHelpAnswer</a>
</li>
</ul>
</div>
</div>
<div id="Summarize" style={{marginTop:''100px''}}>点点滴滴</div>
<div id="ProductFunction" style={{marginTop:''500px''}} >fffffffff</div>
<div id="ToHelpAnswer" style={{marginTop:''1000px''}}>wwwwwww</div>






关于使用dva+antd快速构建单页面应用antd dva的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于angularjs – 寻找有关如何构建单个页面应用程序的说明、asp.net-mvc – 如何使用ASP.NET MVC和表单身份验证创建单页面应用程序(SPA)?、Flask + Vue.js:快速实现单页面应用、React单页面应用使用antd的锚点跳转失效的相关知识,请在本站寻找。

本文标签: