使用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 相关文章推荐
javascript下过滤数组重复值的代码
Sep 10 Javascript
预加载css或javascript的js代码
Apr 23 Javascript
jquery showModelDialog的使用方法示例详解
Nov 19 Javascript
JS转换HTML转义符的方法
Aug 24 Javascript
ES6中Math对象新增的方法实例详解
Apr 25 Javascript
微信小程序 页面跳转传值实现代码
Jul 27 Javascript
详解vuex结合localstorage动态监听storage的变化
May 03 Javascript
jQuery中使用validate插件校验表单功能
May 24 jQuery
JS合并两个数组的3种方法详解
Oct 24 Javascript
JavaScript DOM常用操作代码汇总
Jul 03 Javascript
jQuery实现tab栏切换效果
Dec 22 jQuery
Nest.js环境变量配置与序列化详解
Feb 21 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
外媒评选出10支2020年最受欢迎的Dota2战队
2021/03/05 DOTA
消息持续发送的完整例子
2006/10/09 PHP
PHP 字符串加密函数(在指定时间内加密还原字符串,超时无法还原)
2010/04/28 PHP
php url地址栏传中文乱码解决方法集合
2010/06/25 PHP
php _autoload自动加载类与机制分析
2012/02/10 PHP
编写Smarty插件在模板中直接加载数据的详细介绍
2013/06/26 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
phpstudy后门rce批量利用脚本的实现
2019/12/12 PHP
Javascript学习笔记6 prototype的提出
2010/01/11 Javascript
Js表格万条数据瞬间加载实现代码
2014/02/20 Javascript
JavaScript控制各种浏览器全屏模式的方法、属性和事件介绍
2014/04/03 Javascript
jquery插件qrcode在线生成二维码
2015/04/26 Javascript
AngularJS基础学习笔记之控制器
2015/05/10 Javascript
jQuery实现简单的点赞效果
2020/05/29 Javascript
分享javascript计算时间差的示例代码
2020/03/19 Javascript
JS实现微信里判断页面是否被分享成功的方法
2017/06/06 Javascript
element ui里dialog关闭后清除验证条件方法
2018/02/26 Javascript
js+canvas实现验证码功能
2020/09/21 Javascript
node Buffer缓存区常见操作示例
2019/05/04 Javascript
[02:31]2014DOTA2国际邀请赛2009专访:干爹表现出乎意料 看好DK杀回决赛
2014/07/20 DOTA
用Python进行基础的函数式编程的教程
2015/03/31 Python
python字典键值对的添加和遍历方法
2016/09/11 Python
pytorch cnn 识别手写的字实现自建图片数据
2018/05/20 Python
利用python和ffmpeg 批量将其他图片转换为.yuv格式的方法
2019/01/08 Python
python面试题小结附答案实例代码
2019/04/11 Python
Python读取csv文件实例解析
2019/12/30 Python
彻底搞懂 python 中文乱码问题(深入分析)
2020/02/28 Python
美国花布包包品牌:Vera Bradley
2017/08/11 全球购物
Spartoo荷兰:鞋子、包包和服装
2018/07/12 全球购物
计算机软件个人的自荐信范文
2013/12/01 职场文书
教师廉洁自律承诺书
2014/05/26 职场文书
项目申请汇报材料
2014/08/16 职场文书
小学教师师德师风演讲稿
2014/08/22 职场文书
2015年新农村建设指导员工作总结
2015/07/24 职场文书
nginx简单配置多个server的方法
2021/03/31 Servers
python中redis包操作数据库的教程
2022/04/19 Python