上篇文章说道,前段时间忙里偷闲,试了一下vue,搞了个小demo作为练习。原本以为很简单,但实际上耗费时间超出我的想象。如果有客观原因,是vue有自己的私货,另外一个就是缺乏完整的示例,帮助文档搞成手册形式,例子很少,即使有也是支离破碎。再就是所谓免费开源的东西,内容和版本都有点随心所欲,很容易就不被支持,玩似的。
闲话休提。先给出demo的样子。demo很简单,就2个页面,再加一个弹窗,但麻雀虽小,demo里也包含了母版页,部件,路由,以及使用了jquery和国产界面框架layUI。
一、成果
1、首页
底部点击【Test】出次页,点击【About】弹出关于。
2、次页
3、弹出窗口
二、代码文件结构
三、项目搭建
demo最初的基本结构和代码,我是用vue ui命令来生成的。具体可看这个教学视频
四、代码介绍
- 主页面
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- 加载jquery -->
<script type="text/javascript" src="./lib/jquery-1.11.1.min.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
</div>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
这个页面是脚手架自动生成的。这里面有些类似JSP,ASP的标记“<% %>
”,似曾相识,再一次印证了前端开发后端(服务器端)化的感觉。里面的值,大概来自于 /vue.config.js。这个文件也是脚手架生成的。里面的值稍做修改。
// /vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',//直接给出一个路径也可以,如:'/res'
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].title= '资源索引'
return args
})
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 主程序
/src/main.js
import Vue from 'vue'
import router from './routes'
import notfound from './pages/404.vue'
const app = new Vue({
el: '#app',
data: {
currentRoute: window.location.pathname
},
computed: {
ViewComponent() {
const matchingView = router[this.currentRoute]
return matchingView ?
() => import('' + matchingView) :
notfound
}
},
render(h) {
return h(this.ViewComponent)
}
})
//浏览器直接输入地址处理
window.addEventListener('popstate', () => {
app.currentRoute = window.location.pathname
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
里面的代码,主要与路由有关
- 路由
/src/routes.js
export default {
'/': './pages/Home.vue',
'/test': './pages/Test.vue'
}
- 1
- 2
- 3
- 4
这路由代码超简单。但我在路由上花得时间最多。因为许多例子给的都是vue-router,但我试来试去,页面总是出不来,怀疑是vue-router在我安装的各种包里不被支持。官方文档里好像也没提到这个插件,最后只能放弃了。
路由文件虽然简单,但主要由主文件main.js(见上面的主程序)里加载:
import router from './routes'
const app = new Vue({
。。。
data: {
currentRoute: window.location.pathname
},
computed: {
ViewComponent() {
const matchingView = router[this.currentRoute]
return matchingView ?
() => import('' + matchingView) : //最主要的一句
notfound
}
},
。。。
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
官方给出的例子中,使用require("...")
来加载页面,用下载的例子运行的确可以,但移植到我这个项目里,却不行,一模一样的代码。猜测是包的问题。我是用脚手架生成的,代码下来以后,就npm install了,官方这个例子,也许依赖的各种包不一样,所以导致require在我这里就不行,非要import。
路由应用,应用了自定义的VLink.vue
<template>
<div class="hlink" id="flink">
<span>
<v-link href="/">Home</v-link>
</span>
<span>
<v-link href="/test">Test</v-link>
</span>
<span id="about" @click="about"><u>About</u></span>
</div>
</template>
<script>
import VLink from '../components/VLink.vue'
export default {
components: {
VLink
},
mounted() {},
methods: {
about() {
...
}
}
}
</script>
<style>
。。。
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 模板页
/src/layouts/Main.vue,无非就是放置了一个页头、页脚部件。
<template>
<div>
<div>
<Header></Header>
</div>
<div>
<slot></slot>
</div>
<div>
<Footer></Footer>
</div>
</div>
</template>
<script>
import Header from '../components/Header.vue'
import Footer from '../components/Footer.vue'
export default {
components: {
Header,
Footer
}
}
</script>
<style>
...
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 子页
/src/pages/Home.vue
<template>
<main-layout>
<list></list>
</main-layout>
</template>
<script>
import MainLayout from '../layouts/Main.vue'
import List from '../components/List.vue'
export default {
components: {
MainLayout,
List,
}
}
</script>
<style>
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
简单,应用了模板页,以及使用了部件List.vue
- 部件
1)列表
/src/components/List.vue,读取/public/data/里的json文件数据,再显示出来
<template>
<div class="box">
<div class="left">
<ALink v-for="item in projects" :key="item.id" :href="item.url" :title="item.title"
:note="item.note" :note2="item.note2"></ALink>
</div>
<div class="right">
<ALink v-for="item in apps" :key="item.id" :href="item.url" :title="item.title"
:note="item.note" :note2="item.note2"></ALink>
</div>
</div>
</template>
<script>
import ALink from './Link.vue';
import axios from "axios";
export default {
name: 'AppList',
components: {
ALink
},
data() {
return {
projects: [],
apps:[]
}
},
mounted() {
this.getProjects();
this.getApps();
},
methods: {
getProjects() {
axios.get('./data/projects.json').then(response => {
this.projects = response.data;
})
.catch(error => console.log(error));
},
getApps() {
axios.get('./data/apps.json').then(response => {
this.apps = response.data;
})
.catch(error => console.log(error));
}
}
};
</script>
<style>
...
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
json文件没什么特别的
[
{"id":"1","url":"http://192.168.0.22:9999/","title":"共享文档"},
{"id":"https://files.jxasp.com/image/2","url":"http://192.168.0.60/","title":"禅道"},
{"id":"3","url":"http://192.168.0.205:6080/arcgis/rest/services/","title":"https://files.jxasp.com/image/205地图服务"},
{"id":"4","url":"http://192.168.0.22:6080/arcgis/rest/services/","title":"https://files.jxasp.com/image/22地图服务"}
]
- 1
- 2
- 3
- 4
- 5
- 6
2)与路由相关的链接部件
/src/components/VLink.vue
<template>
<a v-bind:href="href" v-bind:class="{ active: isActive }" v-on:click="go">
<slot></slot>
</a>
</template>
<script>
import routes from '../routes'
export default {
props: {
href: {
type: String,
required: true
}
},
computed: {
isActive() {
return this.href === this.$root.currentRoute
}
},
methods: {
go(event) {
event.preventDefault()
this.$root.currentRoute = this.href
window.history.pushState(
null,
routes[this.href],
this.href
)
}
}
}
</script>
<style scoped>
.active {
...
}
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
7、应用第三方框架layUI
layUI是个国产的UI框架,短小精悍,尤其是弹出窗口,可谓经典。怎么与vue结合呢?有人弄了个layui-layer,可以用上layUI的弹窗功能。我开始时直接连接layUI.js,结果系统无法识别layui对象。
npm i -D layui-layer
- 1
/public/index.html里引用jquery
<script type="text/javascript" src="./lib/jquery-1.11.1.min.js"></script>
- 1
vue里使用
/src/components/Footer.vue
<template>
<div class="hlink" id="flink">
...
<span id="about" @click="about"><u>About</u></span>
</div>
</template>
<script>
import layer from 'layui-layer'
import pack from '../../package.json'
export default {
data(){
return {
publicPath:process.env.BASE_URL
}
},
mounted() {},
methods: {
about() {
let version = pack.dependencies.vue;//vue版本号
let content = `<div style='text-align:center;'>
<div><img src='` + this.publicPath + `images/vue.png' /></div>
<div class='ver'><span>Vue version:</span><span>` + version + `</span></div>
</div>`;//路径比较麻烦
layer.open({
type: 1,
skin:'layui-layer-molv',
title: '关于',
maxmin: false,
shade: 0.75,
id: 'lay_about',
moveType: 1,
area: ['450px', '350px'],
btn: ['确定'],
btnAlign: 'c',
content: content
});
}
}
}
</script>
<style>
...
</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- assets
图片是放在 /src/assets/images 下还是放在外面的 /public/images/ ?
这个要看情况。放在assets里,webpack会处理,第一个是文件名会加上哈希值,第二个据说如果图片比较小,内容就会直接被写进页面代码中,这样页面打开时就不用请求了,速度可能会快一点。但如果图片比较大,就还是链接。这个说法我是听别人说的,没能证实。但对于第一点,如果文件名加哈希值,好处是内容更新以后,浏览器没有缓存的问题;但坏处,如果哈希值每次发布都是变的,图片内容又没变的话,那么优点就成为缺点。也许哈希值是不变的,我要了解下。
如果放在public的话,那么就跟以前的方式没啥区别。
五、后记
vue可以让前后端分离真正落地(其他框架也可以做到这一点),而且适合单页应用。单页的话,页面切换,省去了许多请求,用户体验的确是好一些。