我想用vue+vue-vue router view写一个spa但是后端是java我该怎么办

20被浏览7,269分享邀请回答@Controller
public class IndexController {
@RequestMapping("/")
@ResponseBody
public String index() {
return "index";
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "hello";
IndexController类被@Controller标注,其中的两个方法都被@RequestMapping标注,当应用程序运行后,在浏览器中访问http://localhost:8080/,请求会被Spring MVC框架分发到index()方法进行处理。同理,http://localhost:8080/hello会交给hello()方法进行处理。@ResponseBody标注表示处理函数直接将函数的返回值传回到浏览器端显示另外,即使你是jsp页面,返回的也是html01 条评论分享收藏感谢收起使用node+vue.js实现SPA应用
转载 & & 投稿:hebedich
这篇文章主要介绍了使用node+vue.js实现SPA应用的相关资料,需要的朋友可以参考下
最近公司要求开发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__/',
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 =
服务端渲染页面
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"&
&meta charset="utf-8"&
&title&Vue Router Example&/title&
.v-link-active {
//定义一些前端需要用到的全局属性,文章ID或用户信息什么的
//index.ts中传过来的是 window.cm_data = {name:"张三"}
//前端就能访问到了
&%-server_data%&
//这里的id是前端需要用到的一个标识
&div id="app"&
&h1&Hello App!&/h1&
&a v-link="{ path: '/foo' }"&Go to Foo&/a&
&a v-link="{ path: '/bar' }"&Go to Bar&/a&
//router-view是客户端vue-router需要解析的dom
//server_html是根据访问url地址生成的html,是做SEO的重点,不加载下面的app.js也可以看到内容
&router-view& &%-server_html%& &/router-view&
//webpack打包好的js,主要是路由配置
&script src="/__build__/app.js"&&/script&
#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 //前端路由定义,
component: Foo
component: Bar
router.start(App, '#app')
需要完善的地方
前后端统一模板,已经找到方法了把html分离出来,node端用fs.readFileSync方法获取,客户端用webpack的raw-loader获取html内容
不放源码都是瞎扯。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具&nbsp>&nbsp
&nbsp>&nbsp
android教程 &nbsp>&nbsp
【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验
摘要:本文来自于[腾讯bugly开发者社区](/2014th7cj/d/file/p/ayi5zj2v导语最近这几年的前端圈子,由于戏台一般精彩纷呈,从MVC到MVVM,你刚唱罢我登场。backbone,angularjs已成昨日黄花,reactjs如日中天,同时另一更轻量的vue发展势头更猛,尤其是即将release的2.0版本,号称兼具了angularjs和reactjs的两者优点。不过现在的官方版本还是1.0,下面就是基于1.0版本的初体验。##1.为
本文来自于[腾讯bugly开发者社区](/2014th7cj/d/file/p/ayi5zj2v 导语
最近这几年的前端圈子,由于戏台一般精彩纷呈,从 MVC 到 MVVM,你刚唱罢我登场。 backbone,angularjs 已成昨日黄花,reactjs 如日中天,同时另一更轻量的 vue 发展势头更猛,尤其是即将 release 的2.0版本,号称兼具了 angularjs 和 reactjs 的两者优点。不过现在的官方版本还是1.0 ,下面就是基于1.0版本的初体验。
## 1. 为什么要 SPA?
**SPA:** 就是俗称的单页应用(Single Page Web Application)。
在移动端,特别是 hybrid 方式的H5应用中,性能问题一直是痛点。 使用 SPA,没有页面切换,就没有白屏阻塞,可以大大提高 H5 的性能,达到接近原生的流畅体验。
## 2. 为什么选择 vue?
在选择 vue 之前,使用 reactjs 也做过一个小 Demo,虽然两者都是面向组件的开发思路,但是 reactjs 的全家桶方式,实在太过强势,而自己定义的 JSX 规范,揉和在 JS 的组件框架里,导致如果后期发生页面改版工作,工作量将会巨大。
vue 相对来说,就轻量的多,他的view层,还是原来的 dom 结构,除了一些自定义的 vue 指令作为自定义标签以外,只要学会写组件就可以了,学习成本也比较低。
![](/2014th7cj/d/file/p/tf5a1s5ft.png)
## 3. 环境配置
初始化工程,需要 node 环境使用 npm 安装相应的依赖包。
先创建一个测试目录,在里面依次输入以下命令。
//初始化package.json
//安装vue的依赖
npm install vue --save
npm install vue-router --save
//安装webpack的开发依赖
npm install webpack --save-dev
//安装babel的ES6 Loader 的开发依赖
npm install babel --save-dev
npm install babel-core --save-dev
npm install babel-loader --save-dev
npm install babel-preset-es2015 --save-dev
//安装html loacer 的开发依赖
npm install html-loader --save-dev
## 4. 目录结构
src 为开发目录,其中 components 为组件子目录,templates 为模板子目录。
dist 为构建出的文件目录。
index.html 为入口文件。
package.json 为项目描述文件,是刚才 npm init 所建立。
webpack.config.js 是 webpack 的构建配置文件
![](/2014th7cj/d/file/p/frpgu54i.png)
## 5. Webpack 配置
下面是 webpack 的配置文件,如何使用 webpack,请移步 webpack 的官网。```
var webpack= require(&webpack&);
module.exports={
bundle:[ &./src/app.js&]
path:__dirname,
publicPath:&/&,
filename:&dist/[name].js&
{test: //.html$/, loaders: ['html']},
{test: /(/.js)$/, loader:[&babel&] ,exclude:/node_modules/,
presets:[&es2015&]
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
## 6. 入口文件
**index.html**
Vue Router Demo
其中 id 为 app 的 div 是页面容器,其中的 router-view 会由 vue-router 去渲染组件,讲结果挂载到这个 div 上。
**app.js**
var Vue = require('vue');
var VueRouter = require('vue-router');
Vue.use(VueRouter);
Vue.config.debug =
Vue.config.delimiters = ['${', '}']; // 把默认的{{ }} 改成ES6的模板字符串 ${ }
Vue.config.devtools =
var App = Vue.extend({});
var router = new VueRouter({});
router.map(require('./routes'));
router.start(App, '#app');
router.go({&path&:&/&});
这是 vue 路由的配置。 其中由于习惯问题,我把 vue 默认的{{ }} 改成了的 ${ },总感觉这样看模板,才顺眼一些。
**routes.js**
module.exports = {
component: require('./components/index')
'/list': {
component: require('./components/list')
component: require('./components/notFound')
## 7. 第一个组件
**components/index.js**
module.exports = {
template: require('../templates/index.html'),
ready: function () {
**templates/index.html**
Hello World Index!
**执行 webpack 构建命令**
![](/2014th7cj/d/file/p//rfwvptyrdmb.jpg)
**浏览器中访问:**
![](/2014th7cj/d/file/p//ifhdcoaqsvq.png)
**查看 bundle 源码:**
![](/2014th7cj/d/file/p/el2kypxlda.jpg)
发现 template 模板文件,已经被 webpack 打成字符串了。这其中,其实是 webpack 的 html-loader 起的作用
## 8. 组件之间跳转
修改刚才的 index 组件,增加一个跳转链接,不用 href 了,要用 vue 的指令 v-link。
Hello World Index!
添加 list 组件
**components/list.js**
module.exports = {
template: require('../templates/list.html'),
data:function(){
return {items:[{&id&:1,&name&:&hello11&},{&id&:2,&name&:&hello22&}]};
ready: function () {
**templates/list.html**
Hello List Page!
${item.id} : ${item.name}
v-for 也是 vue 的默认指令,是用来循环数据列表的。
现在开始执行 webpack --watch 命令进行监听,这样就不用每次敲 webpack 命令了。只要开发者每次修改 js 点了保存,webpack 都会自动构建最新的 bundle 文件。
![](/2014th7cj/d/file/p//xizpshtyson.png)
浏览器里试试看:
**index 页**
![](/2014th7cj/d/file/p//apysxrg0bhn.png)
**点击 List Page 跳转到 list 页**
![](/2014th7cj/d/file/p//hqdgivqdok1.png)
Bingo! 单页面两个组件之间跳转切换成功!
## 9. 组件生命周期
修改 **componets/list.js **
module.exports = {
template: require('../templates/list.html'),
data:function(){
return {items:[{&id&:1,&name&:&hello11&},{&id&:2,&name&:&hello22&}]};
},//在实例开始初始化时同步调用。此时数据观测、事件和 watcher 都尚未初始化
init:function(){
console.log(&init..&);
//在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调。但是还没有开始 DOM 编译,$el 还不存在。
created:function(){
console.log(&created..&);
//在编译开始前调用。
beforeCompile:function(){
console.log(&beforeCompile..&);
//在编译结束后调用。此时所有的指令已生效,因而数据的变化将触发 DOM 更新。但是不担保 $el 已插入文档。
compiled:function(){
console.log(&compiled..&);
//在编译结束和 $el 第一次插入文档之后调用,如在第一次 attached 钩子之后调用。注意必须是由 Vue 插入(如 vm.$appendTo() 等方法或指令更新)才触发 ready 钩子。
ready: function () {
console.log(&ready..&);
//在 vm.$el 插入 DOM 时调用。必须是由指令或实例方法(如 $appendTo())插入,直接操作 vm.$el 不会 触发这个钩子。
attached:function(){
console.log(&attached..&);
//在 vm.$el 从 DOM 中删除时调用。必须是由指令或实例方法删除,直接操作 vm.$el 不会 触发这个钩子。
detached:function(){
console.log(&detached..&);
//在开始销毁实例时调用。此时实例仍然有功能。
beforeDestroy:function(){
console.log(&beforeDestroy..&);
//在实例被销毁之后调用。此时所有的绑定和实例的指令已经解绑,所有的子实例也已经被销毁。如果有离开过渡,destroyed 钩子在过渡完成之后调用。
destroyed:function(){
console.log(&destroyed..&);
在浏览器里执行了看看:
**首次进入 List 页面的执行顺序如下:**
![](/2014th7cj/d/file/p//gjwhasc0wgz.jpg)
**此时点一下浏览器的后退,List Component 会被销毁,执行顺序如下:**
![](/2014th7cj/d/file/p/algkcbc2zl.jpg)
**这是官方的生命周期的图:**
![](/2014th7cj/d/file/p//kwzq2fspqpf.jpg)
## 10. 父组件与子组件
在很多情况下,组件是有父子关系的,比如 list 列表组件有个子组件 item
**components/item.js**
module.exports = {
template: require('../templates/item.html'),
props:[&id&,&name&],ready: function () {}
**templates/item.html**
我是subitem: ${id} - ${name}修改 list 组件,添加 item 的引用
**components/list.js**
//引用item组件
import item from &./item&;
module.exports = {
template: require('../templates/list.html'),
data:function(){
return {items:[{&id&:1,&name&:&hello11&},{&id&:2,&name&:&hello22&}]};
}, //定义item组件为子组件
components:{
&item&:item
ready: function () {
```**templates/list.html**
Hello List Page!
```**浏览器里试试看:**
![](/2014th7cj/d/file/p//xe1saip5mwk.png)
子组件成功被调用了
## 11. 组件跳转传参
组件之间的跳转传参,也是一种非常常见的情况。下面为列表页,增加跳转到详情页的跳转,并传参 id 给详情页
**修改路由 routes.js**
module.exports = {
component: require('./components/index')
'/list': {
component: require('./components/list')
//增加详情页的跳转路由,并在路径上加上id传参,具名为name:show
'/show/:id': {
name:&show&,
component: require('./components/show')
component: require('./components/notFound')
添加组件 show
**components/show.js**
module.exports = {
template: require('../templates/show.html'),
data:function(){
return {};
created:function(){
//获取params的参数ID
var id=this.$route.params.
//根据获取的参数ID,返回不同的data对象(真实业务中,这里应该是Ajax获取数据)
if (id==1){
this.$data={&id&:id,&name&:&hello111&,&age&:24};
this.$data={&id&:id,&name&:&hello222&,&age&:28};
ready: function () {
console.log(this.$data);
**templates/show.html**
Hello show page!
name:${name}
age:${age}
**修改 templates/item.html**
我是subitem:
这里 name:'show' 表示具名路由路径,params 就是传参。
**继续浏览器里点到详情页试试:**
![](/2014th7cj/d/file/p//vv2oemujbzd.jpg)
**点击“hello11”,跳转到详情页:**
![](/2014th7cj/d/file/p//vx5ppz0eluw.png)
传参逻辑成功。
## 12. 嵌套路由
仅有路由跳转是远远不够的,很多情况下,我们还有同一个页面上,多标签页的切换,在 vue 中,用嵌套路由,也可以非常方便的实现。
添加两个小组件
**components/tab1.js**
module.exports = {
template: &
Tab1 content&
**components/tab2.js**
module.exports = {
template: &
Tab2 content&
**修改 components/index.js 组件,挂载这两个子组件**
import tab1 from &./tab1&;
import tab2 from &./tab2&;
module.exports = {
template: require('../templates/index.html'),
components:{
&tab1&:tab1,
&tab2&:tab2
ready: function () {}
**在路由里加上子路由**
module.exports = {
component: require('./components/index'),
subRoutes:{
component:require('./components/tab1')
component:require('./components/tab2')
'/list': {
component: require('./components/list')
'/show/:id': {
name:&show&,
component: require('./components/show')
component: require('./components/notFound')
好了,在浏览器里试一下:
**初始状态:**
![](/2014th7cj/d/file/p//tboqyvsz2pw.png)
**点了 tab1,tab2:**
![](/2014th7cj/d/file/p/4ozzirmp.png)
Tab 切换没问题,可是,初始状态显示是空的,能不能默认显示 Tab1 Content 呢?很简单,调整下路由就可以了:
module.exports = {
component: require('./components/index'),
subRoutes:{
//默认显示Tab1
component:require('./components/tab1')
component:require('./components/tab1')
component:require('./components/tab2')
## 13. 业界 vue 使用案例
小米移动官网:/2014th7cj/d/file/p/ih3ofbam
饿了吗招聘:/2014th7cj/d/file/p//gcoorcmmxwh
![](/2014th7cj/d/file/p//pd5irkgz0j1.png)
[腾讯 Bugly](/2014th7cj/d/file/p//mbwb2b2tdio [Crash](/2014th7cj/d/file/p//ivv3bp240ol 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
为您提供0门槛上云实践机会
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验相关信息,包括
的信息,所有【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
服务与支持
账号与支持
关注阿里云
International

我要回帖

更多关于 vue router 传递参数 的文章

 

随机推荐