Fork me on GitHub 盒子
盒子
文章目录
  1. 项目介绍
  2. 文档
  3. Github
  4. 项目开始之前的乱七八糟
  5. 开发步骤
    1. 通过vue官网提供的命令行工具快速搭建一个应用
    2. 取Cnode社区最常用的主题页相关入手
  6. 版本
  7. 缺点与小尾巴
    1. 缺点
    2. 写在结尾的话

vue入门实例-基于vue&vue-router重写Cnode社区

项目介绍

线上实例Demo

涉及到的技术包括但不限于:vuevue-routerwebpackzeptofastclickscss

Tips:vue&vue-router这里使用的是2.0版

文档

文档

Github

Github地址:vue-cnode

线上地址:Demo实例地址

项目开始之前的乱七八糟

最初的设想是完完全全由自己构建,这样能够熟悉全部的过程。

  • 创建项目目录层级(按照脚手架)

  • 创建package.json,然后安装什么babel,各种loader等等一大堆乱七八糟

  • 创建webpack.config.js,配置入口js,生成文件路径,预加载和加载资源等等

  • 引入webpack plugins,通过这个webpack-hot-middleware实现重载

配置了一大堆之后,发现还有问题,然后还需要考虑build的配置,遂,猝,享年1小时。然后果断选择vue官网脚手架入手。

好了,下面进入正题。

开发步骤

通过vue官网提供的命令行工具快速搭建一个应用

Github文档

1
2
3
4
5
6
7
8
# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 安装依赖,走你
$ cd my-project
$ npm install
$ npm run dev

这个时候你会发现my-project项目已经自动创建,文件路径大致如下
Alt text

取Cnode社区最常用的主题页相关入手

大概可以分为主题页,主题详情页,评论点赞等设计到登录的这里暂时跳过,至于为什么?别问我,就是任性。

我这里全部采用单文件组件方式开发,即*.vue

什么是单文件组件?

与vue相关的资源全部放在src文件夹下,无需vue渲染的资源放到static文件夹下,附上开发文件目录

Alt text

  • 我们先来看看main.js
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
// 引入vue
import Vue from 'vue';
// 引入zepto
import $ from 'webpack-zepto';
// 引入vue-router
import VueRouter from 'vue-router';
// 引入路由配置文件
import routes from './routes.js';
// 引入fastclick
import FastClick from 'fastclick';
// 引入页面入口文件,其实这个可以不要,我这里引入的唯一目的就是在App.vue下加载全局通用css
import App from './App.vue'
// ajax设置跨域
$.ajaxSettings.crossDomain = true;
/* eslint-disable no-new */
// 安装VueRouter插件
Vue.use(VueRouter);
// 创建一个router的实例对象
var router = new VueRouter({
routes
});
// 移动端修复点透和延时
FastClick.attach(document.body);
// 创建一个Vue实例对象
var vm = new Vue({
el: "#app", // 挂载元素,这里挂载到index.html中id为app的元素上
router, // 引入路由,等于router: router
template: '<App/>', // 注意:这里如果使用了template,那么<App></App>将会替换你整个id为app的元素,除非里面含有slot标签,你想用render也是一个道理
components: { // 组件引入,App对应的就是<App></App>
App
}
});
  • 接下来看看路由配置routes.js
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
// 引入路由对应的组件
import preLoader from './assets/view/preLoader.vue';
import all from './assets/view/all.vue';
import topic from './assets/view/topic.vue';
import about from './assets/view/about.vue';
export default [
{
path: "/", // 路由路径,当页面路径为.../#/的时候使用组件preLoader去渲染页面
name: "home", // 可以理解为key
component: preLoader // 组件
},
{
path: "/all",
name: "all",
component: all
},
{
path: "/topic/:id",
name: "topic",
component: topic
},
{
path: "/about",
name: "about",
component: about
}
];
  • 如何实现页面跳转,我们来看看根页面的组件preLoader.vue
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
// template里面就是等待渲染html结构
<template>
<div id="pageLoader" v-show="show"><img src="~assets/images/preLoad.gif" alt=""></div>
</template>
<script>
// 不习惯export写法可以用 module.exports = {}
export default {
name: 'preLoader',
data (){
return {
show: true
}
},
mounted: function () {
// 往this.$router里push一个name为all的对象,意味着路由将跳转到/#/ + all => /#/all,这里还有其他的模式,不论
setTimeout (() => {
this.$router.push({
name: 'all'
});
this.show = false;
},1314);
}
}
</script>
// 这里如果要使用scss的话必须加上lang="scss",为了让ide不报错,给style加上rel跟type如下就可以了
// 注意:vue-cli默认最后是编译处理css的,这里想使用scss必须安装style-loader和vue-style-loader,不需要改webpack配置
<style rel="stylesheet/scss" type="text/css" lang="scss">
.main-wrap { position: relative; max-width: 750px; min-width: 320px; margin: 0 auto; width: 100%; min-height: 100%;}
#pageLoader { position: fixed; left: 50%; top: 50%; transform: translate(-50%,-50%) translateZ(0); width: 160px; height: 20px;}
</style>
  • 页面跳转之后进入到主题的列表页all.vue,template跟style没什么好说的,正常写吧,来看看script部分
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 引入组件
import $ from 'webpack-zepto';
import backTop from '../components/backtop.vue';
export default {
name: "all",
components: {
backTop,
},
filters: {
getFreeTime: function (time) { // 这里是自定义过滤器,由于vue2.0干掉了默认提供的filters,所以要使用的话需要自行编写
// Code
return time
}
},
data (){
return {
SCROLL_LOCK: false, // 滚动锁,在ajax触发之后完成之前保证不会再次发出请求
menuShow: false, // menu菜单控制器
topics: [], // 数据
params: { // 请求参数
page: 1,
limit: 20,
tab: 'all',
mdrender: true
}
}
},
mounted: function () { // 当结构挂载之后
// 这里就是我们要做的事情了...
// 先判断是否存在tab
if (this.$route.query && this.$route.query.tab) {
this.params.tab = this.$route.query.tab; // 当前所在类别
$(".menu-list a").eq(this.getTitle(this.$route.query.tab).idx).addClass("active").siblings("a").removeClass("active");
} else {
$(".menu-list a").eq(0).addClass("active").siblings("a").removeClass("active");
}
// 请求数据,这里提为一个methods了,因为存在多次调用
this.getTopics();
$("body").removeClass("os-mode");
// 滚动
var self = this;
$(window).on("scroll", function () {
self.getScrollData()
})
},
methods: {
getTitle: function (val) {
// 获取动态的标题
return obj;
},
getTopics: function (type) { // 请求数据
var self = this;
$.get("https://cnodejs.org/api/v1/topics", self.params, function (res) {
if (res && res.data) { // 如果查到数据
self.SCROLL_LOCK = true;
self.topics = res.data;
}
})
},
// 滚动加载数据
getScrollData() {
if (this.SCROLL_LOCK) {
var totalheight = $(window).height() + $(window).scrollTop();
if ($(document).height() <= totalheight + 200) {
this.SCROLL_LOCK = false;
this.params.limit += 20;
this.getTopics();
}
}
},
// 显示sidebar
openMenu: function () {
this.menuShow = true;
$("body").addClass("os-mode");
},
// 收起sidebar
closeMenu: function () {
this.menuShow = false;
$("body").removeClass("os-mode");
},
},
computed: { // 计算属性,适用于频繁变动
title: function () {
return this.getTitle(this.params.tab).title;
},
getOpenClass: function () {
if (this.menuShow) {
return "open";
} else {
return "";
}
}
},
watch: { // 监听器
$route: function (to, from) { // 这里是核心,监听$route(路由的配置对象),一旦这玩意变了,就肯定有情况
// 如果是当前页面切换分类的情况
if (to.query && to.query.tab) {
this.params.tab = to.query.tab;
$(".menu-list a").eq(this.getTitle(to.query.tab).idx).addClass("active").siblings("a").removeClass("active");
} else {
$(".menu-list a").eq(0).addClass("active").siblings("a").removeClass("active");
}
this.getTopics();
// 隐藏导航栏
this.menuShow = false;
$("body").removeClass("os-mode");
}
}
}
  • 一个完整的组件就大概是上述几个步骤了,按照源码安装编写试试吧

版本

1.0.0

缺点与小尾巴

缺点

  • 其实里面组件分的并不细,比如header、sidebar都可以单独抽出来作为组件存在,可以减少代码量

  • 还可以拓展评论,登录,用户信息等一些列CNode API提供的功能页面

  • 如果没有脚手架,直接上手开发复杂度不低

  • 这里还没有引入vuex做状态管理,如果涉及到非父子组件通信建议使用

写在结尾的话

CNode项目还是比较建议作为一个vue&vue-router的入门级练手项目,因为里面实际上涉及到了单页路由的切换管理,同时也实现了日常开发的一些基本功能:包括tab页签切换,ajax请求数据,能够满足日常项目的基本要求。

特别简单的页面不建议使用,正常html+css+js的效率远高于使用vue.


如果能给您带去些许帮助,鄙人不甚欢心。如有错误,恳请交流指出,谢谢!
转载请注明出处:http://mcchen.club/


支持一下
扫一扫,支持McChen