使用node+vue.js实现SPA应用


Posted in Javascript onJanuary 28, 2016

业务需求

最近公司要求开发web版的app,由于app是偏向内容方面,而且带了一个聊天模块,所以一般的多页开发不是很适合,而且主要是手机浏览,对加载速度或者用户体验来说都比较苛刻。调研了很多框架和模式,最后自己东拼西凑搞出来了这么一个玩意。

服务端

毫无疑问使用node,使用typescript可以有效的在编码同时查错,强类型语言写服务端毫无压力。

#app.ts 只贴重要代码

var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var WebpackConfig = require('./webpack.config')

import * as index from "./routes/index";
import * as foo from "./routes/foo";
import * as bar from "./routes/bar";

var app = express();

//启动服务的时候 打包并监听客户端用到的文件,webpackDevMiddleware是开发模式,他会打包js在内存里面,你改了文件,它也会重新打包
app.use(webpackDevMiddleware(webpack(WebpackConfig), {
  publicPath: '/__build__/',
  stats: {
    colors: true
  }
}));

//一般的配置项
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('view options', { layout: false });
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(express.static(__dirname + '/public'));

var env = process.env.NODE_ENV || 'development';
if (env === 'development') {
  app.use(errorHandler());
}

//路由配置
app.get('/', index.index);
app.get('/foo', foo.index);
app.get('/bar', bar.index);


app.listen(3000, function(){
  console.log("Demo Express server listening on port %d in %s mode", 3000, app.settings.env);
});

export var App = app;

服务端渲染页面

#index.ts
import express = require("express")
import vueServer = require("vue-server") //服务端渲染vue的插件

var Vue = new vueServer.renderer(); //创建一个服务端的vue

export function index(req: express.Request, res: express.Response) {

  //创建一个组件
  var vm = new Vue({
    template: `
    <p>This is index!</p>
    `
  });

  //等待html渲染完成,再返回给浏览器 vueServer.htmlReady是vue-server的自带事件
  vm.$on('vueServer.htmlReady', function(html:string) {
    //这里用的是ejs模板 可以把需要用到的数据设置成window下的全局变量,方便客户端的js访问。
    res.render('layout',{server_html:html,server_data:'window.cm_data = {name:"张三"}'})
  });

};
#layout.ejs 访问这个SPA的所有url返回的都是这个页面 <meta>标签都可以动态设置,只要传参数进来就可以
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Vue Router Example</title>
  <style>
    .v-link-active {
      color: red;
    }
  </style>
  <script>
    //定义一些前端需要用到的全局属性,文章ID或用户信息什么的
    //index.ts中传过来的是 window.cm_data = {name:"张三"}
    //前端就能访问到了
    <%-server_data%>
  </script>
</head>
<body>

//这里的id是前端需要用到的一个标识
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <a v-link="{ path: '/foo' }">Go to Foo</a>
    <a v-link="{ path: '/bar' }">Go to Bar</a>
  </p>
  //router-view是客户端vue-router需要解析的dom
  //server_html是根据访问url地址生成的html,是做SEO的重点,不加载下面的app.js也可以看到内容
  <router-view> <%-server_html%> </router-view>
</div>
//webpack打包好的js,主要是路由配置
<script src="/__build__/app.js"></script>
</body>
</html>

客户端

#app.js 这个是/__build__/app.js,可以用es6编写,webpack会转换的

import Vue from './vue.min' //客户端的vue.js
import VueRouter from './vue-router.min' //vue的路由插件,配合webpack可以很简单实现懒加载

//懒加载路由 只有访问这个路由才会加载js
import Foo from 'bundle?lazy!../../components/foo' //配合webpack的bundle-loader,轻松实现懒加载
import Bar from 'bundle?lazy!../../components/bar'
import Index from 'bundle?lazy!../../components/index'

var App = Vue.extend({})

Vue.use(VueRouter)

var router = new VueRouter({
  //这里要好好说一下,一定要设置html5模式,不然前后端URL不统一会发生问题
  //比如访问 http://localhost:3000/ 服务端定义是访问index.ts这个路由文件
  //如果不是html5模式的话,经过客户端js运行之后会变成http://localhost:3000/#!/
  
  //在比如直接浏览器输入 http://localhost:3000/foo 服务端定义是访问.ts这个路由文件
  //如果不是html5模式的话,经过客户端js运行之后会变成 http://localhost:3000/foo/#!/
  
  //设置了html5模式后,加载完js后不会加上#!这2个类似锚点的字符,实现前后端路由统一如果用户刷新浏览器的话,服务端也能渲染出相应的页面。
  history: true, //html5模式 去掉锚点 
  saveScrollPosition: true //记住页面的滚动位置 html5模式适用
})

//定义路由,要和服务端路由路径定义的一样
router.map({
  '/'  : {
    component: Index //前端路由定义,
  },
  '/foo': {
    component: Foo
  },
  '/bar': {
    component: Bar
  }
})

//启动APP
router.start(App, '#app')

需要完善的地方

前后端统一模板,已经找到方法了把html分离出来,node端用fs.readFileSync方法获取,客户端用webpack的raw-loader获取html内容

不放源码都是瞎扯。

源码地址

https://github.com/yjj5855/node-vue-server-webpack

Javascript 相关文章推荐
文字不间断滚动(上下左右)实例代码
Apr 21 Javascript
js仿土豆网带缩略图的焦点图片切换效果实现方法
Feb 23 Javascript
Angularjs的Controller间通信机制实例分析
Nov 07 Javascript
解析Javascript单例模式概念与实例
Dec 05 Javascript
利用vue.js插入dom节点的方法
Mar 15 Javascript
整理关于Bootstrap过渡动画的慕课笔记
Mar 29 Javascript
浅谈如何使用 webpack 优化资源
Oct 20 Javascript
JS返回顶部实例代码
Aug 09 Javascript
vue+jquery+lodash实现滑动时顶部悬浮固定效果
Apr 28 jQuery
jQuery实现获取form表单内容及绑定数据到form表单操作分析
Jul 03 jQuery
vue-router权限控制(简单方式)
Oct 29 Javascript
浅谈vue单页面中有多个echarts图表时的公用代码写法
Jul 19 Javascript
jQuery+css实现的tab切换标签(兼容各浏览器)
Jan 28 #Javascript
javascript实现随机显示星星特效
Jan 28 #Javascript
基于javascript实现全国省市二级联动下拉选择菜单
Jan 28 #Javascript
JS实现动态生成表格并提交表格数据向后端
Nov 25 #Javascript
jQuery+css实现的时钟效果(兼容各浏览器)
Jan 27 #Javascript
jQuery实现的分子运动小球碰撞效果
Jan 27 #Javascript
jQuery+css3实现转动的正方形效果(附demo源码下载)
Jan 27 #Javascript
You might like
将OICQ数据转成MYSQL数据
2006/10/09 PHP
php变量范围介绍
2012/10/15 PHP
php页码形式分页函数支持静态化地址及ajax分页
2014/03/28 PHP
中高级PHP程序员应该掌握哪些技术?
2016/09/23 PHP
php基于curl实现随机ip地址抓取内容的方法
2016/10/11 PHP
!DOCTYPE声明对JavaScript的影响分析
2010/04/12 Javascript
jquery实现图片翻页效果
2013/12/23 Javascript
JS+CSS实现大气清新的滑动菜单效果代码
2015/10/22 Javascript
jQuery实现每隔几条元素增加1条线的方法
2016/06/27 Javascript
Bootstrap中表单控件状态(验证状态)
2016/08/04 Javascript
jQuery通过ajax快速批量提交表单数据
2016/10/25 Javascript
通过修改360抢票的刷新频率和突破8车次限制实现方法
2017/01/04 Javascript
Vue.js 中的 $watch使用方法
2017/05/25 Javascript
基于vue-cli vue-router搭建底部导航栏移动前端项目
2018/02/28 Javascript
微信小程序视图容器(swiper)组件创建轮播图
2020/06/19 Javascript
微信小程序实现多选功能
2018/11/04 Javascript
vue中组件的过渡动画及实现代码
2018/11/21 Javascript
微信小程序如何连接Java后台
2019/08/08 Javascript
深入浅析vue全局环境变量和模式
2020/04/28 Javascript
Python学习笔记之常用函数及说明
2014/05/23 Python
Python简单删除目录下文件以及文件夹的方法
2015/05/27 Python
浅谈python抛出异常、自定义异常, 传递异常
2016/06/20 Python
对Django项目中的ORM映射与模糊查询的使用详解
2019/07/18 Python
django项目简单调取百度翻译接口的方法
2019/08/06 Python
python函数声明和调用定义及原理详解
2019/12/02 Python
基于python及pytorch中乘法的使用详解
2019/12/27 Python
使用pytorch实现可视化中间层的结果
2019/12/30 Python
深入了解NumPy 高级索引
2020/07/24 Python
Python2与Python3关于字符串编码处理的差别总结
2020/09/07 Python
彻底解决Python包下载慢问题
2020/11/15 Python
音乐专业应届生教师求职信
2013/11/04 职场文书
大学生毕业自我评价范文分享
2013/11/07 职场文书
土木工程个人自荐信范文
2013/11/30 职场文书
禁毒宣传工作方案
2014/05/23 职场文书
最新离婚协议书范本
2014/08/19 职场文书
庆祝国庆节标语
2014/10/09 职场文书