哈喽你们周一好,今天的内容比较多,主要就是包括:把前端页面的展现页给搭出来,而后调通接口API,能够添加数据,这两天我也一直在开发,原本想一篇一篇的写,发现可能会比较简单,就索性把项目搭建的过程简化,一次写好了,在开发 Nuxt.js 框架的过程当中,我发现相比以前仍是有些变化的,若是你是读过我第一个先后端分离系列的小伙伴,可能看过我简单说过Nuxt框架的一些知识《Nuxt.js 是什么?》,我发现如今在项目搭建的过程当中,已经优化了一些功能,今天就重头搭建一下。css
若是你没有看过以前的文章,能够简单看看,主要是看看理论方面,若是是只想看搭建过程,直接看这个便可了,毕竟如今已是最新的了,老的方案能够舍弃,不过我的建议,前边那几篇能够花几分钟看看,了解下,好比:什么是SSR渲染,为啥要使用它,是如何进行渲染的等等,毕竟不少基础概念我这里不会再说了,由于这是一个只有四篇的小系列,在上个系列都会有说到,这里就很少叙述了,直接进行项目的搭建。html
今天是从简到繁的过程,并不会把每一个页面的说明都写上,由于页面是千篇一概的,项目设计只写这一篇吧,下一篇重点说如何服务端部署。如今已经基本完成了(由于我尚未来得及发布,若是你想如今查看具体的效果,能够下载下来运行便可,注意要配置我们的Blog.Core 项目,也能够关注的 Github 地址 https://github.com/anjoy8/Nuxt.tBug,这两天我会发布一版本,在线地址:http://123.206.33.109:7090/):前端
这里咱们就直接使用了官方脚手架工具建立,固然你也能够一步一步的建立,手动建立比较麻烦,不适合新手,想了解更多,查看官网:新手模板。vue
这里默认你的电脑上已经安装了 npm 环境了,若是不肯定是否安装了,能够查使用命令查看 npm -v:ios
不只如此,若是你想使用官方脚手架搭建项目,要确保npm版本在 5.2+ ,目前已是6.5.0了,个人本地是 5.6.0 ,符合要求,开始动手搭建。git
首先你找好一个放置你项目的文件夹做为你的仓库,而后经过CMD或者 PowerShell 来建立项目,很简单 :github
npx create-nuxt-app 项目名
在安装的过程当中,会出现几个选项,这里先放上个人动图,具体如何选,图下我会解释:web
具体的选择是这样的:数据库
Project name TiBug.Nuxt //项目名称 Project description //项目描述 Use a custom server framework //选择通用的服务端渲染模板框架:none,是默认服务 Nuxt default serve Use a custom UI framework //选择通用UI框架:Element Choose rendering mode //选择渲染模式:SSR或SPA Use axios module //是否使用 axios 进行http请求:yes Use eslint //是否使用代码格式纠错: no,会各类格式警告 Use prettier //是否代码美化:yes Author name //做者名 Choose a package //选择一个包管理:npm
你能够根据状况本身去选择,好比你不喜欢用 nuxt 自带的服务器渲染,想使用 Express ,好比你能够直接在这里就选择好你喜欢的样式,好比我就喜欢 ElementUI 样式框架。这相对之前的版本,已经有很大的改观了,我认为很棒的。npm
这样咱们就等待安装成功了,中间可能大概须要2~5分钟,看我的网络而定。
安装好后,咱们会看到生成的所有文件夹,并且是已经安装好依赖包的:
若是你稍微有一些 Vue 的开发经验,应该都能知道大概的文件夹包含的意思,好比Component,Pages,Store等,我们具体说说每个文件夹都是干啥的:
├── assets // 资源文件。用于组织未编译的静态资源入LESS、SASS 或 JavaScript │ └── logo.jpg // 默认logo图片 ├── components // 组件。用于本身编写的Vue组件,好比滚动组件,日历组件,分页组件 │ └── AppLogo.vue // 默认logo组件 ├── layouts // 布局。页面都须要有一个布局,默认为 default。它规定了一个页面如何布局页面。全部页面都会加载在布局页面中的 <nuxt /> 标签中。 │ └── default.vue // 默认模板页面,相似mvc中的layout ├── middleware // 中间件。存放中间件。能够在页面中调用: middleware: 'middlewareName' 。 ├── pages // 页面。一个 vue 文件即为一个页面。 │ └── index.vue // 默认首页面 ├── plugins // 用于存放JavaScript插件的地方 │ └── element-ui.js // 上边咱们安装的UI框架 ├── static // 用于存放静态资源文件,好比图片,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。 ├── store // 用于组织应用的Vuex 状态管理。 ├── .editorconfig // 开发工具格式配置 ├── .eslintrc.js // ESLint的配置文件,用于检查代码格式 ├── .gitignore // 配置git不上传的文件 ├── nuxt.config.js // 用于组织Nuxt.js应用的个性化配置,好比网站title,已便覆盖默认配置 ├── package.json // npm包管理配置文件 └── README.md // 说明文档
其实整理看起来,和以前的没多少差异,至少在页面结构上没太大差异,主要更新是把项目搭建前的配置交给了开发者了,不过有一个地方是被去掉了的,你先和 Vue 结构对比下,看看少了一个什么配置。
你们看上边的文档架构层次图,你可能会发现,nuxt 和 vue 仍是有些不同的,这里没有了 路由Route 的配置,发现了么?
这个就是 nuxt 框架的独到之处,为了能实现更好的SSR渲染,它使用的是根据页面结构,自动路由,因此你的文件名,就是你的路由名称:
在 Nuxt.js 里面定义带参数的动态路由,须要建立对应的如下划线做为前缀的 Vue 文件 或 目录。
如下目录结构:
pages/ --| _slug // 如下划线开头的文件夹,表明参数 -----| comments.vue -----| index.vue --| users/ -----| _id.vue //以 下划线 开头的页面,动态路由 --| index.vue
Nuxt.js 生成对应的路由配置表为:
router: { routes: [ { name: 'index', path: '/', component: 'pages/index.vue' }, { name: 'users-id', path: '/users/:id?', component: 'pages/users/_id.vue' }, { name: 'slug', path: '/:slug', component: 'pages/_slug/index.vue' }, { name: 'slug-comments', path: '/:slug/comments', component: 'pages/_slug/comments.vue' } ] }
具体的请查看官网:路 由
我在webstorm 中运行上边搭建好的项目,能够看到初始欢迎页:
下边咱们就正式对这个页面进行完善,进行总体设计。
下边我就简要的写了,具体的代码,请看个人 Github 地址就行。我这里先把 pages/index.vue 的默认内容清空,
这个时候你能够先练习练习,布局页面在哪里配置?先停下来想想,或者看看刚刚建立的文件夹,没错,就是 layouts 文件夹下的 default.vue 页面,我们看看这个初始的是什么样子:
<template> <div> <nuxt/> //这个就是页面入口,其余页面就是在这里进行嵌入的,能够对比MVC中 layout.cshtml 中的 @RenderBody() </div> </template> <style> </style>
咱们直接对其进行改造,设计模板结构,
<template> <div id="app"> <el-row :gutter="0" > <el-col class="nav"> <el-col class="nav-bar" :sx="22" :sm="22" :md="22" :lg="16"> <div class="nav-bar-body"> <div class="nav-bar-inner"> <div id="logo"> <img src="../assets/logoa.png" /> </div> </div> ............ </el-row> <div class="footer">京ICP备xxxxxxxx号</div> </div> </template>
由于我已经在安装的时候,选择了ElementUI 框架,因此能够直接使用相关 el 组件,而不用在各类配置和引用了,你必定会问:以前在开发 Vue 的时候,也使用过 ElementUI 呀,不是应该先安装,而后在 Mian.js 中引用么,但是你为啥直接就能够用呢?能提这个问题的,表示真的是已经看懂了,别着急,请往下看。
首先,咱们应该清楚插件是什么?
插件其实就是一个 .js 文件,将咱们须要的组件注入到咱们的项目中去,可拔插,很方便替换任何一个咱们须要的。
其实,咱们应该了解插件是在哪里定义:
(一样,你这里也能够先停一停,本身去文件夹里找找,感受哪个像是定义插件的),在脚手架总体结构中,咱们知道每个文件夹都有本身的做用,其中 plugins 文件夹,就是用来存放咱们的插件的,插件目录 plugins
用于组织那些须要在 根vue.js应用
实例化以前须要运行的 Javascript 插件。说人话就是,咱们的vue项目想要运行,必须实例化 vue,这个你们确定都知道,那实例化以前,固然就必需要加载插件了,就是这个目的。
咱们在上边用官方脚手架搭建的时候,已经安装了 elementUI 的插件,因此咱们会在 plugins 文件夹里,看到这个 elemengt-ui.js 文件:
之后咱们若是还须要创建其余组件的话,都在这里处理,好比之后咱们会对axios请求访问进行封装插件,若是你不是很明白,这里举个栗子:
若是你是一直看个人文章,必定知道我在第一个系列的 Vue 项目里,为了进行 axios 请求,建立了一个 http.js 的问题,这个其实就是一个插件:
我定义好之后,并在 main.js 中注册引入,这样在其余页面内,就能够随心使用了。
最后,咱们应该知道如何注册这些插件:
这个时候,就用到咱们的配置文件: nuxt.config.js 了,这里边就是咱们整个项目的配置文件,好比 head 中的 title 、icon呀,还有css,还有跨域本地代理,最后,固然就是咱们的插件注册了:
这个时候,咱们从新运行下咱们的项目(注意:若是修改了nuxt.config.js,要从新编译下),这个时候咱们看下效果:
嗯,很正常的显示了,而且已经支持了SSR渲染,感受很开心,就是样式太丑,那咱们就须要添加进一个样式文件,在根目录下新建 style 文件夹,并添加 style.css,具体的直接从 Github 拉取便可,不过,不只仅要添加这个文件,还要在配置文件中,进行注册引用,
页面 Banner 最终的效果是这样的:
咱们页面的模板已经加载好了,而且也 mock 了专题的数据,剩下的就是首页结构了。
这里由于和 vue 中开发组件或页面是同样的,就很少说了,具体的代码能够参考个人 Github 代码,这里把结构说一下:
其中最重要的,就是 asyncData 异步数据加载,这个和 vue 仍是不一样的:
asyncData
方法会在组件(限于页面组件)每次加载以前被调用。它能够在服务端或路由更新以前被调用。 在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你能够利用asyncData
方法来获取数据,Nuxt.js 会将asyncData
返回的数据融合组件data
方法返回的数据一并返回给当前组件。
是在页面加载以前,加载数据,而后融合着 data ,一块儿返回,最后渲染页面。注意:因为asyncData
方法是在组件 初始化 前被调用的,因此在方法内是没有办法经过 this
来引用组件的实例对象。
我这里经过编译后的代码,能够看到是异步请求数据是这样的,下文中,我会配合着 axios 异步请求,一块儿说说:
data: function data() { return { data: 0, }; }, asyncData: function () { var _asyncData = _babel_runtime_helpers_asyncToGenerator__WEBPACK_IMPORTED_MODULE_2___default()( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(_ref) { var params, tag, _ref2, data; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: params = _ref.params; _context.prev = 1; tag = params.tag; _context.next = 5;//axios http数据请求 return _plugins_axios__WEBPACK_IMPORTED_MODULE_3__["default"].get("/api/TopicDetail?page=1&tname=".concat(tag)); case 5: _ref2 = _context.sent; data = _ref2.data.data; console.log(data); debugger; return _context.abrupt("return", { tagList: data.data, tagtitle: tag, fadetitle: true, notfound: !data.data.length }); case 12: _context.prev = 12; _context.t0 = _context["catch"](1); case 14: case "end": return _context.stop(); } } }, _callee, this, [[1, 12]]); })); function asyncData(_x) { return _asyncData.apply(this, arguments); } return asyncData; }(), components: { ArticleList: _components_ArticleList__WEBPACK_IMPORTED_MODULE_4__["default"] },
除了上边的首页之外,还有详情页,分类页,以及数据添加页,这里就过多的说明了,其中主要说的是:
这个其实很简单的,就是在 mounted() 中,注册浏览器滚动事件就行了,若是这里你不知道 mounted 是vue生命周期的何时的话,就应该好好的再学学了,由于生命周期钩子是很重要的,至少我我的任务是这样的:
在created的时候,视图中的html并无渲染出来,因此此时若是直接去操做html的dom节点,必定找不到相关的元素而在 mounted中,因为此时html已经渲染出来了,因此能够直接操做dom节点。
这个时候咱们就自定义事件:
//页面渲染完毕后,监听滚动事件 mounted() { window.addEventListener('scroll', this.handleScroll) }, methods: { //处理方法,在页面具体底部30像素的时候,触发事件 handleScroll() { const jrscrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollT let scrollBottom = document.body.clientHeight - window.innerHeight - jrscrollTop if (scrollBottom < 30) { if (this.ScrollFirst) { this.nextpage() //触发这个,下拉加载分页事件 } } } }, //记得在销毁当前页面的时候,也就是切换的时候,把监听去掉 beforeDestroy() { window.removeEventListener('scroll', this.handleScroll, fa }
总体很简单,和咱们的平时的 JS 上拉加载很类似,具体的能够查看个人代码。
这里若是你有必定的 Vue 开发基础,应该能会八成以上,为何是八成呢,由于可能仍是会有一些小问题须要注意,好比重点的就是异步数据加载了。
由于 Nuxt.js 是基于SSR渲染的,因此必须先获取到数据,而后生成 Html 片,才能去渲染,这个和客户端渲染仍是不同的,客户端二者能够同步,甚至先渲染,再去进行 axios 数据请求,可是这样不能实现 SEO 的做用,因此就在原先 axios 请求的基础上,封装了一个异步请求,这样就能达到目的。可是这个在使用的时候,可能不是很顺手,由于不少人已经习惯了直接用固然组件的 data() 中的数据了,在上边咱们也看到了,asyncData 编译后的模板,它其实也是当前组件页面中 data 的一部分,咱们甚至就能够当成 data 来使用,只不过这个data里,能够写逻辑,能够进行 axios 异步请求,那下边我们就看看具体用法:
首先咱们应该说说如何定义这个插件,固然,咱们在每个页面,经过引入 axios 也行,可是这样有一些问题,除了不方便觉得,还有一个就是没法定义一些公共的东西,好比 api 域名路径,因此,咱们须要定义一个插件:
A:首先,咱们在 plugins 文件夹中定义 axios.js 插件:
import axios from 'axios'//引入 axios 服务 let options = {} if (process.server) { // 配置基路由 options.baseURL = 'http://localhost:5000' // http://123.xx.xx.xx:5000(服务端地址) } export default axios.create(options) // 注意这里是直接 export 了一个对象实例,而不是 Vue.use,这个插件不须要注册
B:在页面中使用:
这里聪明的你可能看到了,为何没有像 element-ui 插件那样,没有在 nuxt.config.js 中配置这个插件???
这里说下,由于这里是直接返回的一个对象,咱们不须要关心是否是要去安装它,它不像 element和下边的markdown那样,咱们只有安装了才能用,由于element和 markdown 不是一个返回值的状态,而是 Vue.use ,是直接集成到了 vue 对象内的,因此须要在项目配置文件中进行安装,这里的 axios.js 插件就不须要安装,若是你还不明白的话,我用 http.js 也封装了一个插件,一个就像 element那样,集成到vue 的插件:
这样的话,咱们在组件页面中,就能够直接这么用:
const {data: {response}} = await Vue.http.get('/api/TopicDetail/'+ id);//这个就是使用到了 Vue 对象
因此这个就须要安装,由于咱们必须在 app(也就是vue)被实例化以前,安装这个插件:
若是你还看不懂 axios.js插件(返回对象,可直接使用)和 http.js插件(集成到vue对象里,须要注册),这二者之间的区别的话,请留言,或者加群,我详细给你说说。
C:最后为了使用接口,咱们须要进行跨域,使用 proxy 代理:
proxy: [ ['/api', { target: 'http://localhost:5000' }], ['/images', { target: 'http://localhost:5000' }],// 将图片也代理到本地,下文的<上传图片>栏目会说到 // ['/api', { target: 'http://123.xx.xx.xx:3080' }],//服务端配置 ]
//还有这里
modules: [
// Doc: https://github.com/nuxt-community/axios-module#usage
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
D:接下来咱们就说说如何进行异步获取数据
就拿咱们的首页数据加载来讲,咱们的需求是加载出来所有的 Bug 数据,首先 index.vue 中确定有一些基本的数据,好比当前页数等常量参数,这些参数不须要咱们异步去获取,由于它们在页面渲染以前已经被定义了:
//当前组件中的数据变量 data() { return { page: 0, lastpage: true, ScrollFirst: true, }; },
可是,上边咱们也说了,咱们为了实现 SSR 渲染,必须在渲染前就要异步获取数据,因此这里咱们就使用到了异步数据加载 asyncData:
// 一共有三种方法,这个最经常使用的一种方法,asyncData() 方法 async asyncData({ params }) { try { // 路由参数 const { tag } = params // 获取异步获得的数据,必须使用 {} 大括号包裹 let { data } = await axios.get(`/api/TopicDetail/24`) console.log(data) // 若是想要获取返回数据 data 中的某一个属性,能够这么嵌套 const { data: { article } } = await axios.get(`/api/TopicDetail?page=1`) console.log(article) // 而后将获得的数据返回过去,其实和自己的 data() 有殊途同归之妙 return { articleList: article, tagtitle: tag, fadetitle: true, notfound: !article.length } } catch (err) { error({statusCode: 404}) } },
提示:若是你不须要使用异步的话,直接用 let data= axios.get(`/api/TopicDetail/24`) 就能够了。
其实经过这里,你应该也能看的明白,这个异步获取数据,自己和 data() 是很像的,经过操做,把数据返回到页面里,这里只是要注意两点:
一、必定要是异步的 await;
二、必定注意返回的数据格式,你能够用debugger 或者 console 来查看,也能够直接用 mock 数据测试。
最后,就是像 data 数据同样,直接在页面其余地方进行使用了,
<el-col :xs="24" :sm="24" :md="24" :lg="12" v-for="item in articleList" :key="item.id" class="artitem" >
若是你是第一次使用,确定会遇到找不到数据而报错的状况,用我说的方法,断点调试+mock 数据,相信很快你会游刃有余了。
关于富文本编辑器,我也找了几个作对比,由于平时更喜欢用 markdown ,因此,就选用了这个 mavon-editor 编辑器了,使用方法很简单,仍是插件三步走:
一、安装依赖:
npm install mavon-editor --save
二、在plugins中建立vue-markdown.js
import Vue from 'vue' import mavonEditor from 'mavon-editor' Vue.use(mavonEditor)
三、在nuxt.config.js中引入
具体如何在详情页展现呢,我用的是 highlight.js 和 marked 来实现的,使用方法很简单,安装过包之后,在页面内引用,而后对咱们添加的 content 代码进行 marked() 方法便可,具体使用请查看个人代码。
这个上传图片仍是比较简单的,只不过须要有一些细节须要注意下,我这里有两个版本的上传图片的方法 ,一个是 element-upload 上传用户头像的,一个是 mavon 富文本编辑器中的上传图片的方法,后台方法是同一个,只不过前端控制稍微不一样罢了,这里先说下后端API:
[HttpPost] [Route("Pic")] public async Task<MessageModel<string>> InsertPicture([FromServices]IHostingEnvironment environment) { var data = new MessageModel<string>(); string path = string.Empty; string foldername = "images"; var files = Request.Form.Files; if (files == null || files.Count() <= 0) { data.Msg = "请选择上传的文件。"; return data; } //格式限制 var allowType = new string[] { "image/jpg", "image/png", "image/jpeg" }; string folderpath = Path.Combine(environment.WebRootPath, foldername); if (!System.IO.Directory.Exists(folderpath)) { System.IO.Directory.CreateDirectory(folderpath); } if (files.Any(c => allowType.Contains(c.ContentType))) { if (files.Sum(c => c.Length) <= 1024 * 1024 * 4) { //foreach (var file in files) var file = files.FirstOrDefault(); string strpath = Path.Combine(foldername, DateTime.Now.ToString("MMddHHmmss") + file.FileName); path = Path.Combine(environment.WebRootPath, strpath); using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { await file.CopyToAsync(stream); } data = new MessageModel<string>() { Response = strpath, Msg = "上传成功", Success = true, }; return data; } else { data.Msg = "图片过大"; return data; } } else { data.Msg = "图片格式错误"; return data; } }
而后看看前端是怎么操做的:
一、element-ui 的 upload 上传图片方法:
这个很简单,官方栗子中,已经说的很明白了,几乎不用作任何的修改就能达到目的,只须要咱们修改下后端的api地址便可,注意这里有跨域的问题,我直接用的是本地代理的地址:
注意注意下边三个问题就好了:
一、接口地址配置在 action;
二、必定要跨域,本项目使用的是本地代理 proxy,你也可使用后端的CORS实现跨域;
三、记得要在后端配置使用静态资源文件 app.UseStaticFiles(); ,由于我把图片放到了wwwroot里了;
其余的和官方地址如出一辙的。http://element-cn.eleme.io/#/zh-CN/component/upload
二、mavon 富文本编辑器上传图片 :
这个彻底照搬官方文档便可,几乎不用修改什么,只不过注意事项仍是上边的那三个,跨域+静态资源使用,很少说:图片上传详情点击这里...,或者看个人Github代码。
我这里使用了异步的统一泛型返回数据模型,你们也都能看懂,由于第一个系列已经说的不少了:
/// <summary> /// 获取Bug数据列表(带分页) /// </summary> /// <param name="page">页数</param> /// <param name="tname">专题类型</param> /// <returns></returns> [HttpGet] public async Task<MessageModel<PageModel<TopicDetail>>> Get(int page = 1, string tname = "") { var data = new MessageModel<PageModel<TopicDetail>>(); int intTotalCount = 6; int TotalCount = 0; int PageCount = 1; List<TopicDetail> topicDetails = new List<TopicDetail>(); //总数据,使用AOP切面缓存 topicDetails = await _topicDetailServices.GetTopicDetails(); if (!string.IsNullOrEmpty(tname)) { var tid = (await _topicServices.Query(ts => ts.tName == tname)).FirstOrDefault()?.Id.ObjToInt(); topicDetails = topicDetails.Where(t => t.TopicId == tid).ToList(); } //数据总数 TotalCount = topicDetails.Count; //总页数 PageCount = (Math.Ceiling(topicDetails.Count.ObjToDecimal() / intTotalCount.ObjToDecimal())).ObjToInt(); //当前页数据 topicDetails = topicDetails.OrderByDescending(d => d.Id).Skip((page - 1) * intTotalCount).Take(intTotalCount).ToList(); return new MessageModel<PageModel<TopicDetail>>() { Msg = "获取成功", Success = topicDetails.Count >= 0, Response = new PageModel<TopicDetail>() { page = page, pageCount = PageCount, dataCount = TotalCount, data = topicDetails, } }; }
通用返回信息类 和 通用分页类:
/// <summary> /// 通用返回信息类 /// </summary> public class MessageModel<T> { /// <summary> /// 操做是否成功 /// </summary> public bool Success { get; set; } = false; /// <summary> /// 返回信息 /// </summary> public string Msg { get; set; } = "服务器异常"; /// <summary> /// 返回数据集合 /// </summary> public T Response { get; set; } } /// <summary> /// 通用分页信息类 /// </summary> public class PageModel<T> { /// <summary> /// 当前页数 /// </summary> public int page { get; set; } = 1; /// <summary> /// 总页数 /// </summary> public int pageCount { get; set; } = 6; /// <summary> /// 数据总数 /// </summary> public int dataCount { get; set; } = 0; /// <summary> /// 返回数据 /// </summary> public List<T> data { get; set; } }
由于咱们的TiBug 1.0 尚未设计用户登陆问题,因此,这一块尚未,不过别慌,过些天我会加上,这几天先把1.0版本发布到服务器。
而后开始开发 TiBug 1.5版本,设计管理后台,初步是基于VueAdmin的,主要是用户管理和Bug管理,权限管理等,你们也看到了,目前的版本是只能添加不能修改,仍是基于咱们以前设计的 [Authorize("Permission")],数据库配置,我本地简单试了试,仍是挺好用的,到时候也会尝试下滑动过时等问题的解决方案。
到这里咱们已经把项目的结构定义好了,并且也自适应了设备,内容简单,主要的就是讲解了:
一、如何经过 nuxt 官方脚手架搭建项目;二、页面是如何加载的;三、插件的使用;四、异步数据运行;五、使用富文本编辑器以及上传图片等等,做为展现。
这几天把总体页面都设计好了,也上传到Github上了,下篇开始部署,发布到服务器。