vue构建单页面应用实战
发布时间 - 2026-01-11 00:35:30 点击率:次1. 为什么要 SPA?

SPA: 就是俗称的单页应用(Single Page Web Application)。
在移动端,特别是 hybrid 方式的H5应用中,性能问题一直是痛点。 使用 SPA,没有页面切换,就没有白屏阻塞,可以大大提高 H5 的性能,达到接近原生的流畅体验。
2. 为什么选择 vue?
在选择 vue 之前,使用 reactjs 也做过一个小 Demo,虽然两者都是面向组件的开发思路,但是 reactjs 的全家桶方式,实在太过强势,而自己定义的 JSX 规范,揉和在 JS 的组件框架里,导致如果后期发生页面改版工作,工作量将会巨大。
vue 相对来说,就轻量的多,他的view层,还是原来的 dom 结构,除了一些自定义的 vue 指令作为自定义标签以外,只要学会写组件就可以了,学习成本也比较低。
3. 环境配置
初始化工程,需要 node 环境使用 npm 安装相应的依赖包。
先创建一个测试目录,在里面依次输入以下命令。
//初始化package.json npm init //安装vue的依赖 npm install vue --save npm install vue-router --save //安装webpack的开发依赖 npm install webpack --save-dev 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 的构建配置文件
5. Webpack 配置
下面是 webpack 的配置文件,如何使用 webpack,请移步 webpack 的官网。
var webpack= require("webpack");
module.exports={
entry:{
bundle:[ "./src/app.js"]
},
output:{
path:__dirname,
publicPath:"/",
filename:"dist/[name].js"
},
module:{
loaders:[
{test: /\.html$/, loaders: ['html']},
{test: /(\.js)$/, loader:["babel"] ,exclude:/node_modules/,
query:{
presets:["es2015"]
}
}
]
},
resolve:{
},
plugins:[
/*
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
*/
]
}
6. 入口文件
index.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue Router Demo</title> </head> <body> <div id="app"> <router-view></router-view> </div> <script src="dist/bundle.js"></script> </body> </html>
其中 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 = true;
Vue.config.delimiters = ['${', '}']; // 把默认的{{ }} 改成ES6的模板字符串 ${ }
Vue.config.devtools = true;
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
<h1>Index</h1> <hr/> <p>Hello World Index!</p>
执行 webpack 构建命令
浏览器中访问:
查看 bundle 源码:
发现 template 模板文件,已经被 webpack 打成字符串了。这其中,其实是 webpack 的 html-loader 起的作用
8. 组件之间跳转
修改刚才的 index 组件,增加一个跳转链接,不用 href 了,要用 vue 的指令 v-link。
<h1>Index</h1>
<hr/>
<p>Hello World Index!</p>
<p><a v-link="{path:'/list'}" >List Page</a></p>
添加 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
<h1>List</h1>
<hr/>
<p>Hello List Page!</p>
<ul>
<li v-for="(index,item) in items">
${item.id} : ${item.name}
</li>
</ul>
v-for 也是 vue 的默认指令,是用来循环数据列表的。
现在开始执行 webpack --watch 命令,这样就不用每次敲 webpack 命令了。只要开发者每次修改 js 点了保存,webpack 都会自动构建最新的 bundle 文件。
浏览器里试试看:
index 页
点击 List Page 跳转到 list 页
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 页面的执行顺序如下:
此时点一下浏览器的后退,List Component 会被销毁,执行顺序如下:
这是官方的生命周期的图:
10. 父组件与子组件
在很多情况下,组件是有父子关系的,比如 list 列表组件有个子组件 item
components/item.js
module.exports = {
template: require('../templates/item.html'),
props:["id","name"],
ready: function () {
}
};
templates/item.html
<p>我是subitem: ${id} - ${name}</p>
修改 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
<h1>List</h1> <hr/> <p>Hello List Page!</p> <ul> <li v-for="(index,item) in items"> <!--使用item子组件,同时把id,name使用props传值给item子组件--> <item v-bind:id="item.id" v-bind:name="item.name"></item> </li> </ul>
浏览器里试试看:
子组件成功被调用了
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;
//根据获取的参数ID,返回不同的data对象(真实业务中,这里应该是Ajax获取数据)
if (id==1){
this.$data={"id":id,"name":"hello111","age":24};
}else{
this.$data={"id":id,"name":"hello222","age":28};
}
},
ready: function () {
console.log(this.$data);
}
};
templates/show.html
<h1>Show</h1>
<hr/>
<p>Hello show page!</p>
<p>id:${id}</p>
<p>name:${name}</p>
<p>age:${age}</p>
修改 templates/item.html
复制代码 代码如下:
<p>我是subitem: <a v-link="{name:'show',params: { 'id': id } }"> ${id} : ${name}</a> </p>
这里 name:‘show’ 表示具名路由路径,params 就是传参。
继续浏览器里点到详情页试试:
点击“hello11”,跳转到详情页:
传参逻辑成功。
12. 嵌套路由
仅有路由跳转是远远不够的,很多情况下,我们还有同一个页面上,多标签页的切换,在 vue 中,用嵌套路由,也可以非常方便的实现。
添加两个小组件
components/tab1.js
module.exports = {
template: "<p>Tab1 content</p>"
};
components/tab2.js
module.exports = {
template: "<p>Tab2 content</p>"
};
修改 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:{
"/tab1":{
component:require('./components/tab1')
},
"/tab2":{
component:require('./components/tab2')
}
}
},
'/list': {
component: require('./components/list')
},
'/show/:id': {
name:"show",
component: require('./components/show')
},
'*': {
component: require('./components/notFound')
}
}
好了,在浏览器里试一下:
初始状态:
点了 tab1,tab2:
Tab 切换没问题,可是,初始状态显示是空的,能不能默认显示 Tab1 Content 呢?很简单,调整下路由就可以了:
module.exports = {
'/': {
component: require('./components/index'),
//子路由
subRoutes:{
//默认显示Tab1
"/":{
component:require('./components/tab1')
},
"/tab1":{
component:require('./components/tab1')
},
"/tab2":{
component:require('./components/tab2')
}
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# vue单页面应用
# vue.js 单页面应用
# vue单页面应用demo
# 跳转
# 是由
# 详情页
# 器里
# 这是
# 我是
# 跳转到
# 点了
# 自定义
# 试试看
# 绑定
# 配置文件
# 就可以
# 都是
# 情况下
# 文档
# 还没有
# 好了
# 是有
# 第一个
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
Thinkphp 中 distinct 的用法解析
什么是JavaScript解构赋值_解构赋值有哪些实用技巧
大连 网站制作,大连天途有线官网?
如何正确选择百度移动适配建站域名?
php485函数参数是什么意思_php485各参数详细说明【介绍】
济南网站建设制作公司,室内设计网站一般都有哪些功能?
如何在IIS管理器中快速创建并配置网站?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
详解Android图表 MPAndroidChart折线图
Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?
详解MySQL数据库的安装与密码配置
Laravel如何连接多个数据库_Laravel多数据库连接配置与切换教程
如何快速生成专业多端适配建站电话?
javascript基于原型链的继承及call和apply函数用法分析
Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
如何用花生壳三步快速搭建专属网站?
如何快速搭建高效香港服务器网站?
Laravel如何使用查询构建器?(Query Builder高级用法)
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
Laravel如何实现用户注册和登录?(Auth脚手架指南)
公司门户网站制作流程,华为官网怎么做?
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?
php 三元运算符实例详细介绍
如何自定义建站之星网站的导航菜单样式?
如何将凡科建站内容保存为本地文件?
详解jQuery中的事件
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
浅析上传头像示例及其注意事项
Laravel怎么发送邮件_Laravel Mail类SMTP配置教程
长沙企业网站制作哪家好,长沙水业集团官方网站?
清除minerd进程的简单方法
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】
怎样使用JSON进行数据交换_它有什么限制
北京的网站制作公司有哪些,哪个视频网站最好?
大同网页,大同瑞慈医院官网?
Laravel如何使用Blade组件和插槽?(Component代码示例)
如何生成腾讯云建站专用兑换码?
Laravel如何实现API版本控制_Laravel版本化API设计方案
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
Laravel怎么实现搜索功能_Laravel使用Eloquent实现模糊查询与多条件搜索【实例】
使用豆包 AI 辅助进行简单网页 HTML 结构设计

