【vue】实现前端题库—小案例

为了更好的学习vue的知识,趁着周末闲暇时间,利用vue+vant编写一个前端题库,并且把案例部署到gitee上面,方便之后去看一些基础知识运用的题目,牢固基础知识点。

持续更新中......(2021-2-2:10.00)

更新部分ES6和react题目(2021-3-1)

gitee案例地址:http://hanbin666.gitee.io/lmeyjs/#/index

根据原型图,大致的实现一个简单的题目+答案的功能,主要分三个页面:1、index-->技术类型分类;2、list-->技术知识集合列表;3、pageContent-->具体知识点

准备工作

vue手脚架搭建基本的页面、引入vant、Vue-Router、Vuex、本地数据(有服务器,可以用网络数据)

import './plugins/vant.js'
import 'amfe-flexible';
import router from './router/router'
import store from './store/store'
// vant.js
import Vue from 'vue'
// eslint-disable-next-line no-unused-vars
import Vant, { Locale } from 'vant'
import 'vant/lib/index.css'
import '../vant-variables.less'

Vue.use(Vant)
Vue.use(Locale)
// router
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter);

const routes = [
  {path: '/', redirect:'/index'},
  {path: '/index', name:'index', component:() => import('../view/index.vue')},
  {path: '/list', name:'list', component:() => import('../view/list.vue')},
  {path: '/pageContent', name:'pageContent', component:() => import('../view/pageContent.vue')},
]

const router = new VueRouter({
  // mode: 'history',
  base: '/LmeyJs',
  routes
})

export default router
// vuex
import Vue from 'vue'
import Vuex from 'vuex'
import Result from '../unit/result'

Vue.use(Vuex)

const store = new Vuex.Store({
  state:{
    label:'',
    result:Result,
  },

  //getters可以认为是store的计算属性
  getters: {
    getLabel(state) {
      return state.label
    },
    getResult(state) {
      return state.result
    }
  },
    //存放同步函数方法
    mutations:{
      setLabel(state,newLabel){
        state.label = newLabel //设置新的值
      }
    },

    //存放异步函数方法
    actions:{
      /*
      //使用解构赋值,commit调用mutatios方法
      setNewLabel({commit},newLabel){
        commit('setLabel',newLabel) //提交mutations方法
      },*/
    }
});

export default store
// 本地数据
const result = [
  {label:"vue",question:"Vue.observable你有了解过吗?说说看",answer:'Vue10001',id:"Vue10001"},
  {label:"vue",question:"vue渲染模板时怎么保留模板中的HTML注释呢",answer:'Vue10002',id:"Vue10002"},
  {label:"vue",question:"你知道style加scoped属性的用途和原理吗?",answer:'Vue10003',id:"Vue10003"},
  {label:"vue",question:"你期待vue3.0有什么功能或者改进的地方?",answer:'Vue10004',id:"Vue10004"},
  {label:"vue",question:"vue边界情况有哪些?",answer:'Vue10005',id:"Vue10005"},
  {label:"vue",question:"如何在子组件中访问父组件的实例?",answer:'Vue10006',id:"Vue10006"},
  {label:"vue",question:"watch的属性用箭头函数定义结果会怎么样?",answer:'Vue10007',id:"Vue10007"},
  {label:"vue",question:"在vue项目中如果methods的方法用箭头函数定义结果会怎么样?",answer:'Vue10008',id:"Vue10008"},
];
export default result

1、index.vue界面

首页是一个NavBar和一个Layout布局,在data里面放需要的遍历的元素,加上点击事件,并获取点击事件的一些参数,传递到下个页面

// 存放遍历的数据
label: [
          {
            id: 1132,
            title: "ECMAScript",
            pic: 'https://atts.w3cschool.cn/attachments/cover/cover_javascript.png?imageView2/1/w/64/h/64&t=1572425981'
          },
          {
            id: 1133,
            title: "NodeJs",
            pic: "https://webjike.com/upload/images/2018/3/caa3b227baad960e.jpg"
          },
          ......
        ]

每一个事件的点击,给路由跳转附带两个参数,这里传递参数用query方法传递,主要是为了在下面的页面使用时,刷新页面数据不会丢失,如果用parmas传递参数,页面刷新,数据会丢失。 

 methods:{
      handleOpen(e,label){
        let listId = e.currentTarget.dataset.list; 
        window.localStorage.setItem('listId',listId); // 缓存到本地,其他界面用
        window.localStorage.setItem('label',label); // 缓存到本地,其他界面用
        this.$router.push({
          path:'/list',
          query:{
            listId:listId,
            label:label
          }
        });
      }
    }

2、list.vue界面

list界面是根据不同的listId和label来显示不同知识点的具体列表内容,即不同url,列如:http://localhost:8080/LmeyJs/#/list?listId=1134&label=vue

不同的内容显示,可以通过label来筛选,label即是分类,例如label = [vue,React,NodeJs,....],label的获取是路由跳转到list界面时获取到的,所以label在beforeRouteEnter导航守卫中获取一下,如果直接在

mounted是无法获取到变化的label的,因此要在即将进入界面时获取,即在beforeRouteEnter中获取。

beforeRouteEnter(to,from,next){
      next(vm =>{
        vm.label = to.query.label
      })
    },
// 通过label的类别筛选,告诉list界面,具体显示哪种类别的题目
computed:{
      resultList:function () {
        let label = this.label;
        return this.result.filter(function (title) {
          return title.label === label;
        })
      }
    },

同样的,在进入下个页面时,把参数也带过去

openContent(id){
        this.$router.push({
          path:'/pageContent',
          query:{
            id:id,
            index:index,
            total:this.total
          }
        });
      }

3、pageContent.vue界面

这里主要是问题显示、参看答案和上、下题的展示。

同样的,在进入界面时,需要获取变化的值,这理变化的值是:每一个题目的唯一id,在list界面中,点击传过来的id,获取变化的值,可以在pageContent.vue中监听路由的变化

watch: {
      // '$route'(val) {
      //   console.log(val.query.id);
      // }
}

不给它有一个缺点,就是在第一次点击进来的时候,是获取不到id的,因此,还是需要在beforeRouteEnter导航守卫中获取

/* 修改BUG:2021-02-02
beforeRouteEnter(to, from, next) {
     next(vm =>{
        vm.id = to.query.id; // 给id赋值
        vm.index = to.query.index; // 获取进入页面的index
        vm.total = to.query.total; // 获取该类别的总数据
        vm.activeNames = []; // 折叠面板默认收起
        vm.content = vm.$store.state.result; // 获取准备好的本地数据
        for (let i = 0; i < vm.content.length; i++) {
          if (vm.content[i].id === vm.id) {
            vm.question = vm.content[i].question;
            vm.answer = vm.content[i].answer;
          }
        }
      });
    },
*/

beforeRouteEnter(to, from, next) {
     next(vm =>{
        vm.label = from.query.label; //获取动态的label
        vm.id = to.query.id; // 给id赋值
        vm.index = to.query.index; // 获取进入页面的index
        vm.total = to.query.total; // 获取该类别的总数据
        vm.activeNames = []; // 折叠面板默认收起
        let theContent = []; // 定义数组,保存分类后的数据
        let content = vm.$store.state.result; // 获取准备好的本地数据
        for (let i = 0; i < content.length; i++) {
          if (content[i].id === vm.id) {
            vm.question = content[i].question;
            vm.answer = content[i].answer;
          }
          // 遍历所有数据,同类的放到一个数组中
          if(content[i].label === vm.label){
            theContent.push(content[i]);
          }
        }
        vm.content = theContent; // 传回给页面渲染
      });
    },

 数据是一个数组,通过url传递明显不合理。

方法一:在页面加载的时候,先在mounted遍历一次,用于该页面刷新时,数据不会丢失。

 mounted() {
      let theContent = [];
      let content = this.$store.state.result;
      this.label = window.localStorage.getItem('label');
      for (let i = 0; i < content.length; i++) {
        if (content[i].id === this.id) {
          this.question = content[i].question;
          this.answer = content[i].answer;
        }
        if(content[i].label === this.label){
          theContent.push(content[i]);
        }
      }
      this.content = theContent;
     
    },

方法二: mounted的代码和beforeRouteEnter中的代码存在着大量重复的代码,为了简化重复代码,可以把数据存到sessionStorage中

 const value = _this.data;
 window.sessionStorage.setItem('shopData', JSON.stringify(value));

在pageContent中载入数据,由于数据存在缓存中,因此页面刷新不会导致数据丢失,同时也简化了代码

 vm.data= window.sessionStorage.getItem('shopData')?JSON.parse(window.sessionStorage.getItem('shopData')):{};

 

methods: {
      // 点击下一题时
      handleAdd() {
        this.activeNames = [];
        if (+this.index < +this.total) {
          this.index++;
          this.question = this.content[this.index - 1].question;
          this.answer = this.content[this.index - 1].answer;
        } else if (this.index > this.total) {
          this.index = this.total;
        }
      },
    // 点击上一题时
      handleSub() {
        this.activeNames = [];
        if (this.index > 1) {
          this.index--;
          this.question = this.content[this.index - 1].question;
          this.answer = this.content[this.index - 1].answer;
        } else if (this.index < 1) {
          this.index = 1;
        }
      },
      // 返回list界面,传递回参数
      onClickLeft() {
        this.$router.push({
          path: '/list',
          query: {
            listId: window.localStorage.getItem('listId'),
            label: window.localStorage.getItem('label'),
          }
        });
      },

    }

案例地址:http://hanbin666.gitee.io/lmeyjs/#/index

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值