为了更好的学习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'),
}
});
},
}