Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
ChenJiaH opened this issue Aug 1, 2019 · 0 comments
Open

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

ChenJiaH opened this issue Aug 1, 2019 · 0 comments

Comments

@ChenJiaH
Copy link
Owner

ChenJiaH commented Aug 1, 2019

首发于微信公众号《前端成长记》,写于 2016.12.23

介绍

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

  • vue
  • vue-router
  • webpack
  • zepto
  • fastclick
  • scss

Tips: vue&vue-router 使用的为 2.x 版

线上地址

https://chenjiahao.xyz/vue-cnode

开发步骤

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

  • 创建项目目录层级(按照脚手架)
  • 创建package.json,然后安装什么babel,各种loader等等一大堆乱七八糟
  • 创建webpack.config.js,配置入口js,生成文件路径,预加载和加载资源等等
  • 引入webpack plugins,通过这个webpack-hot-middleware实现重载

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

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

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

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

image

文章编写时 cli 版本为 2.x

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

大概可以分为主题页,主题详情页,评论点赞等涉及到登录的这里暂时跳过。

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

什么是单文件组件?

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

image

  1. 我们先来看看main.js
// 引入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
  }
});
  1. 接下来看看路由配置routes.js
// 引入路由对应的组件
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
  }
];
  1. 如何实现页面跳转,我们来看看根页面的组件preLoader.vue
// 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>
  1. 页面跳转之后进入到主题的列表页all.vue,template跟style没什么好说的,正常写吧,来看看script部分
// 引入组件
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");
    }
  }
}

** 一个完整的组件就大概是上述几个步骤了,按照源码安装编写试试吧 **

缺点与小尾巴

缺点

  • 其实里面组件分的并不细,比如header、sidebar都可以单独抽出来作为组件存在,可以减少代码量
  • 还可以拓展评论,登录,用户信息等一些列CNode API提供的功能页面
  • 如果没有脚手架,直接上手开发复杂度不低
  • 这里还没有引入vuex做状态管理,如果涉及到非父子组件通信建议使用

写在结尾的话

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

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

(完)


本文为原创文章,可能会更新知识点及修正错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验
如果能给您带去些许帮助,欢迎 ⭐️star 或 ✏️ fork
(转载请注明出处:https://chenjiahao.xyz)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant