关键词搜索

源码搜索 ×
×

一个vue小demo代码介绍

发布2020-10-15浏览1046次

详情内容

上篇文章说道,前段时间忙里偷闲,试了一下vue,搞了个小demo作为练习。原本以为很简单,但实际上耗费时间超出我的想象。如果有客观原因,是vue有自己的私货,另外一个就是缺乏完整的示例,帮助文档搞成手册形式,例子很少,即使有也是支离破碎。再就是所谓免费开源的东西,内容和版本都有点随心所欲,很容易就不被支持,玩似的。

闲话休提。先给出demo的样子。demo很简单,就2个页面,再加一个弹窗,但麻雀虽小,demo里也包含了母版页,部件,路由,以及使用了jquery和国产界面框架layUI。

一、成果

1、首页
在这里插入图片描述
底部点击【Test】出次页,点击【About】弹出关于。

2、次页
在这里插入图片描述
3、弹出窗口
在这里插入图片描述

二、代码文件结构

在这里插入图片描述

三、项目搭建

demo最初的基本结构和代码,我是用vue ui命令来生成的。具体可看这个教学视频

四、代码介绍

  1. 主页面

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
  1. 主程序

/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

里面的代码,主要与路由有关

  1. 路由

/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
  1. 模板页

/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
  1. 子页

/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. 部件
    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
  1. assets
    图片是放在 /src/assets/images 下还是放在外面的 /public/images/ ?

这个要看情况。放在assets里,webpack会处理,第一个是文件名会加上哈希值,第二个据说如果图片比较小,内容就会直接被写进页面代码中,这样页面打开时就不用请求了,速度可能会快一点。但如果图片比较大,就还是链接。这个说法我是听别人说的,没能证实。但对于第一点,如果文件名加哈希值,好处是内容更新以后,浏览器没有缓存的问题;但坏处,如果哈希值每次发布都是变的,图片内容又没变的话,那么优点就成为缺点。也许哈希值是不变的,我要了解下。

如果放在public的话,那么就跟以前的方式没啥区别。

五、后记

vue可以让前后端分离真正落地(其他框架也可以做到这一点),而且适合单页应用。单页的话,页面切换,省去了许多请求,用户体验的确是好一些。

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载