Vue 项目实战

13 篇文章 3 订阅
订阅专栏

前言

为了练习Vue,写了一个小项目,主要内容是答题。

项目简介
  • ElementUI框架
  • 无后端,数据来源为本地JSON文件
    • 也可以改造成有后端的,查找题目种类就在后端完成
  • 比较原生,适合刚刚接触Vue,想做练习的同学
  • 笔者水平有限,如有不严谨之处请多多批评
预览图
主页/开始页

在这里插入图片描述

答题页

在这里插入图片描述

正文

1. 初始化项目
  • 使用脚手架创建项目,cli3.x,选择router即可
  • 添加element,详见 在vue中使用elementUI
  • 安装axios
2. 在views文件夹中创建如下目录

在这里插入图片描述

3. 写路由
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const Main = () => import('@/views/Main')
const Quiz = () => import('@/views/quiz/Quiz')
const Start = () => import('@/views/quiz/Start')

const routes = [
    {
        path: '/',
        redirect: '/index',
        component: Main,
        children: [
            {
                path: '/index',
                component: Start
            },
            {
                path: '/quiz',
                component: Quiz
            },
        ]
    },
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

export default router

非常简单的路由设计,其中的路由的加载方式为懒加载。

4. 主页
4.1 布局
  <div>
    <h3>你好,请选择答题范围</h3>
    <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
    <div style="margin: 15px 0;"></div>
    <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
      <el-checkbox @change="isDisabled" v-for="city in cities" :label="city" :key="city">{{ city }}</el-checkbox>
    </el-checkbox-group>
    <el-button type="primary" @click="start" :disabled="btnDisabled" style="margin-top: 2rem;">
      开始答题
    </el-button>
  </div>
4.2 逻辑
export default {
  name: "Start",
  data() {
    return {
      checkAll: false,
      btnDisabled: false,
      checkedCities: ['文科', '理科'],
      cities: ['文科', '理科', '娱乐', '生活', '文艺', '流行'],
      isIndeterminate: true
    };
  },
  created() {
    this.checkedCities = localStorage.checkedWords ? localStorage.checkedWords.split(',') : this.checkedCities
  },
  methods: {
    isDisabled() {
      this.btnDisabled = this.checkedCities.length === 0
    },
    handleCheckAllChange(val) {
      this.checkedCities = val ? this.cities : [];
      this.isIndeterminate = false;
      this.isDisabled()
    },
    handleCheckedCitiesChange(value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.cities.length;
      this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length;
    },
    start() {
      this.$set(localStorage, 'checkedWords', this.checkedCities)
      this.$router.push('/quiz')
      this.$emit('checked', this.checkedCities, true)
    }
  }
}
  • created函数,在创建组件完成后,检查浏览器缓存localStorage中是否已经存在选择的题目范围。如果有则直接使用,没有就使用默认选择的。
    • 注意,数组储存到localStorage中,是以,隔开的字符串形式,所以要用split函数来分割一下。用法详见 字符串方法
  • isDisabled函数是用来判断选中题目种类的个数是否为0,如果是则按钮不可点击。
  • start函数按钮点击后触发,目的是跳转路由至/quiz答题页,并将题目种类数组传给父组件Main
    • 传给父组件的目的是,通过父组件再传给兄弟组件Quiz,即子传父,父传其他子,也可以用过vuex实现。
5. Main主框架
5.1 布局
<el-container style="height: 40rem; border: 1px solid #eee;">
    <el-header style="background:linear-gradient(to right,#cfd9df,#e2ebf0); height:5rem;">
      <div>
        <h2 style="margin: 1rem 0 0 40%">Vue答题</h2>
        <span style="float: right;">--<a style="color: deepskyblue;"
                                         href="https://blog.csdn.net/qq_44888570">zed</a> 制作</span>
      </div>
    </el-header>
    <el-container style="height: 100%;">
      <el-aside width="15rem" style="background-color: #ccc;height: 100%; padding: 2rem;">
        <h2>历史排行榜</h2>
        <ol>
          <li v-for="item in scores">{{ item }}</li>
        </ol>
      </el-aside>
      <el-main>
        <router-view @checked="setInfo" @score="setScore" :info="info"></router-view>
      </el-main>
    </el-container>
  </el-container>

布局采用ElementUI中如下布局

<el-container>
  <el-header>Header</el-header>
  <el-container>
    <el-aside width="200px">Aside</el-aside>
    <el-main>Main</el-main>
  </el-container>
</el-container>
5.2 逻辑
export default {
  name: "Main",
  data() {
    return {
      info: [],
      scores: localStorage.scores ? localStorage.scores.split(',') : []
    }
  },
  methods: {
    setInfo(data) {
      this.info = data
    },
    setScore(data) {
      this.scores.push(data)
      this.sortArr(this.scores)

      if (this.scores.length > 10) {
        this.scores.splice(10)
      }
      localStorage.scores = this.scores
    },
    sortArr(arr) {
      return arr.sort((x, y) => y - x)
    }
  }
}
  • data中的info数组,就是前面Start组件传过来的数据
  • data中的scores,每次打完题之后,Quiz数组都会将分数传过来。然后将这些分数压入数组,存储到localStorage
  • setInfo函数捕获子组件Start传过来的数据,并赋值给该组件
  • setScore函数捕获子组件Quiz传过来的数据,并压入分数数组,且要排序。如果分数数组的长度超过10,则只截取分数最高的十项
  • sort函数为数组排序,用法详见 数组方法
6. 答题页
6.1 布局
 <div>
    <div style="height: 5rem;">
      <h2 style="float: left;">score:{{ score }}</h2>
      <h2 style="float: left;margin-left: 5rem;">hp:<i class="el-icon-s-opportunity" v-for="value in hp"></i></h2>
    </div>
    <div>
      <span>科目范围:{{ info }}</span>
      <span style="margin-left: 5rem;">本题属:{{ currentQuiz.school }} <i
          class="el-icon-arrow-right"></i> {{ currentQuiz.type }}</span>
    </div>
    <h2>{{ currentQuiz.quiz }}</h2>
    <div style="width: 30rem;">
      <el-progress :percentage="progress.percentage" :format="format" :stroke-width="10"
                   :color="progress.customColors"></el-progress>
    </div>
    <div>
      <el-radio v-for="(item,index) in currentQuiz.options" v-model="answer"
                style="margin-top: 2rem"
                :label="currentQuiz._id + index"
                :class="{'isAnswer' : isAnswer[index]}"
                border>{{ item }}
      </el-radio>
    </div>
    <el-button type="primary" @click="nextBtn" :disabled="btnDisabled" style="margin-top: 2rem">next</el-button>
  </div>
6.2 逻辑
<template>
  <div>
    <div style="height: 5rem;">
      <h2 style="float: left;">score:{{ score }}</h2>
      <h2 style="float: left;margin-left: 5rem;">hp:<i class="el-icon-s-opportunity" v-for="value in hp"></i></h2>
    </div>
    <div>
      <span>科目范围:{{ info }}</span>
      <span style="margin-left: 5rem;">本题属:{{ currentQuiz.school }} <i
          class="el-icon-arrow-right"></i> {{ currentQuiz.type }}</span>
    </div>
    <h2>{{ currentQuiz.quiz }}</h2>
    <div style="width: 30rem;">
      <el-progress :percentage="progress.percentage" :format="format" :stroke-width="10"
                   :color="progress.customColors"></el-progress>
    </div>
    <div>
      <el-radio v-for="(item,index) in currentQuiz.options" v-model="answer"
                style="margin-top: 2rem"
                :label="currentQuiz._id + index"
                :class="{'isAnswer' : isAnswer[index]}"
                border>{{ item }}
      </el-radio>
    </div>
    <el-button type="primary" @click="nextBtn" :disabled="btnDisabled" style="margin-top: 2rem">next</el-button>
  </div>
</template>

<script>

export default {
  name: "Quiz",
  props: {
    info: {
      type: Array
    }
  },
  data() {
    return {
      hp: [1, 1, 1],
      quizzes: [],
      currentQuiz: {},
      answer: 0,
      score: 0,
      btnDisabled: false,
      isAnswer: [false, false, false, false],
      progress: {
        percentage: 100,
        cdTimer: null,
        customColors: [
          {color: '#f56c6c', percentage: 30},
          {color: '#e6a23c', percentage: 60},
          {color: '#5cb87a', percentage: 100}
        ],
      }
    }
  },
  async created() {
    if (this.info.length === 0) {
      this.$message({
        type: 'error',
        message: '请先选择答题范围'
      })
      return this.$router.replace('/index')
    }

    await this.fetch()
    this.filter()
    this.renderQuiz()
  },
  methods: {
    async fetch() {
      const res = await this.$http.get('/quizzes.json')
      this.quizzes = res.data
    },
    format(per) {
      return `${Math.round(per * 0.1)}s`
    },
    filter() {
      //一共六种题目,如果全选则不需要筛选
      if (this.info.length === 6) {
        return
      }
      const newList = this.quizzes.filter(item => {
        return this.info.includes(item.school)
      })
      this.quizzes = newList
    },
    randomQuiz() {
      const currentIndex = Math.round(this.quizzes.length * Math.random())
      this.currentQuiz = this.quizzes[currentIndex]
      this.quizzes.splice(currentIndex, 1)
    },
    renderQuiz() {
      this.randomQuiz()
      this.killProgress()
    },
    killProgress() {
      this.progress.cdTimer && clearInterval(this.progress.cdTimer)
      this.progress.percentage = 100
      this.answer = 0
      this.progress.cdTimer = setInterval(() => {
        if (--this.progress.percentage <= 0) {
          this.nextBtn()
        }
      }, 100)
    },
    //点击next或者到时间
    checkAnswer() {
      return new Promise(resolve => {
        //如果答案正确,则直接下一题,不正确1s延迟后跳转,并且标记出正确答案
        if (this.currentQuiz.answer - 1 + '' === this.answer[this.answer.length - 1]) {
          this.score++
          resolve(true)
        } else {
          this.$set(this.isAnswer, this.currentQuiz.answer - 1, true)
          setTimeout(() => {
            this.$set(this.isAnswer, this.currentQuiz.answer - 1, false)
            this.hp.pop()
            resolve(this.hp.length > 0)
          }, 1000)
        }
      })
    },
    async nextBtn() {
      this.btnDisabled = true
      clearInterval(this.progress.cdTimer)
      if (await this.checkAnswer()) {
        this.renderQuiz()
        this.btnDisabled = false
      } else {
        this.$emit('score', this.score, true)
        this.$router.push('/index')
      }
    }
  }
}
</script>

<style scoped>
.isAnswer {
  border: 2px solid #0f0;
}
</style>
  • created函数
    • 检查父组件传过来的info,即题目种类数组是否为空,如果是空则返回到首页,重新选择。
    • 在组件创建完毕后,就要获取JSON文件的内容了,也就是题目列表。
    • 接下来要根据题目种类数组,来筛选题目
    • 然后开始出题
  • fetch函数用来发送axios请求,这里的axios被笔者挂载到Vue 的原型上,这样便可全局使用。也可以只在该组件中引入axios
    • async && await用法详见轻松理解 async 与 await
    • main.js文件中书写
import axios from "axios"
Vue.prototype.$http = axios
  • filter函数用来过滤题目列表,如果题目列表的长度为6,也就意味着全选,则不用筛选,直接返回。
  • randomQuiz函数用于随机出题,出题之后,为了防止重复,直接在题目列表中删除此题
  • killProgress用于管理进度条计时器
    • 做一些初始化工作。如果计时器已经存在,则先删除;每次都要恢复选中的答案answer值,因为answer只有1,2,3,4,所以恢复为0是可以的;恢复进度条百分比
    • 添加定时器,100ms意味着进度条会在10s后走完。
    • 如果走完,则触发判定答案和重新渲染题目等一系列工作,这些工作都在nextBtn函数中完成。也就是说,进度条走完和点击下一题按钮的效果相同
  • checkAnswer函数用于判定答案的对与错
    • Promise用法详见 Promise详解
    • 由于JSON文件中,每一道题的答案都是根据索引值来判断,且四个选项的索引为1,2,3,4。咱们选择的答案是0,1,2,3,所以要在题目正确答案-1或者再咱们的答案+1,都是可以的。
    • 这里也解释一下,渲染4个选项时,为何label值不直接绑定索引,而是题目的_id再加索引值。这是因为vue读取缓存的机制,这道题的选项的label值如果绑定了1,2,3,4,下道题也是1,2,3,4,这样vue会直接将缓存中的四个选项捞出来,而不是重新创建。这就意味着,咱们上一题的选中效果,切换到下一题的时候,依旧存在。
    • 为何用this.$set赋值,可见 vue响应式详解
    • 回到这个函数的业务,如果说用户答对了此道题,则直接切换到下一题;如果没有答对,则过一秒再切换,为的是让用户看一眼正确答案。返回值是布尔类型,但并不意味着true代表答对了,而是代表hp还是有的,也就是说可以继续出题;false代表hp用完了,不能再继续出题
  • nextBtn函数,一旦点击按钮或者进度条结束,就把按钮变为不可点击,这是为了屏蔽用户的无效操作,而且多次点击有可能导致计时器的混乱。一旦点击按钮或者进度条结束,就要判定是否继续出题;如果继续,则需要把按钮恢复可点击,调用出题函数;如果结束了,则把分数传给父组件Main,并且跳转路由至/index
  • 数据this.hp为何是一个数组呢?这个数组是用来渲染那个灯泡图标的。
    在这里插入图片描述
  • 数据isAnswer,配合选项v-for渲染来绑定样式类。初始该数组里有4个false,一旦进度条结束或点击按钮,则会将正确的那个选项绑定样式类。什么?你说选正确了就不用绑定了是吧?不错,但是正确没有延迟1s切换下一题,用户也就看不到这个效果了。
.isAnswer {
  border: 2px solid #0f0;
}

结语

总的来说,这个项目难度不大,但是一些基础琐碎的知识挺多的,适合练手。

源码

链接:https://pan.baidu.com/s/1HKvGly1H2lpQCkxfm2Onlw
提取码:z1ed

求赞!!!
VUE入门小项目总结
08-20
利用网易云课堂http://study.163.com/course/courseMain.htm?courseId=1004463009  的源代码,一个简单的项目,来记录总结学习VUE的使用博客见https://blog.csdn.net/qq_16546829/article/details/81867611
SpringBoot+vue项目实战(一)
热门推荐
jiuxiang1的博客
02-19 1万+
SpringBoot+vue入门SpringBoot+Vue项目实战一:vue开发步骤一:安装node.js步骤二:安装镜像步骤三:安装Vue步骤四:安装全局vue-cli脚手架步骤五:检查Vue是否安装成功步骤六:创建一个基于 webpack 模板的新项目(可略)步骤七:启动项目,访问项目步骤一:先择file,点击open导入我们的项目步骤二:引入vue插件步骤三:新建两个vue文件步骤四:启动项目二:SpringBoot项目开发步骤1:新建SpringBoot项目步骤2:springboot的crud步
vue3基础入门项目实战实例介绍
最新发布
代上老码的专栏
04-07 268
这个实战项目是一个简单的待办事项管理应用,用户可以添加、编辑和删除待办事项。通过这个项目,你将学习到如何使用 Vue 3 的组件、响应式系统、生命周期钩子以及基本的路由管理。
vue 项目实战
06-17
这是一个入门vue的实战项目,可以提升自己对vue的掌握。
vue项目实战
lqy
12-10 1万+
vue项目实战 1.3 电商后台管理系统的开发模式(前后端分离) 后端负责写接口,管理数据库 前端负责调接口(基于vue技术栈,ajax) 1.4 电商后台管理系统的技术选型 1.前端项目技术栈 vue vue-router(路由) Element-UI(前端UI组件库) Axios(网络数据请求) Echarts(图形化表) 2.后端项目技术栈 Node.js Express Jwt Mysql Sequelize 2.项目初始化 2.1前端项目初始化步骤 安装vue脚手架 npm insta
Vue项目实战
老余的博客
02-20 3119
新建common组件文件夹,新建对应的Header、Footer、Menu这些文件,然后完成Menu菜单,并且新建学生列表、作业列表、信息列表、考勤管理页面,并且配置路由,之后去写面包屑组件。添加 --legacy-peer-deps 指令在下载对应版本的指令后,保证各个依赖之间的不同版本的共存;然后在axios的二次封装的请求头里携带上token,至此,我们的axios二次封装和跨域完美解决。3、开需求分析会(甲方、SE、开发、测试)简单的进行首页、登录页、404页面的搭建。
vue项目实战 vue项目实战
01-20
vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战vue项目实战...
ssm+vue项目实战
11-21
vue实战项目,前端框架使用vue+bootstrap,后端框架使用的是spring+springmvc+mybatis,数据库使用mysql,包含全套代码
vue项目实战总结篇
11-27
这篇文章把小编前段时间做的vue项目,做个完整的总结,具体内容请参考本文。 这次算是详细总结,会从项目的搭建,一直到最后的服务器上部署。 废话不多说了。干货直接上。 一、 必须node环境, 这次就不写node环境的...
vue的一个实战项目
06-16
vue的一个实战项目,比较适合初学者对原理的理解 也适合有一定项目经验的写法借鉴
vue项目实例
04-01
新手学习vue的最佳demo实例,整合了vue的各类组件以及各种指令等等
vue项目实战.zip
11-24
vue视频教程,2019vue实战视频-不止三套 2019vue实战视频-不止三套 vue实战视频
VUE项目实战
DavidFFFFFF的博客
07-29 2259
Vue实战—–用户登录及注册1.用户登录 用户登录页面主要是获取当前页面用户输入的帐号跟密码,验证是否为空并通过VUE axios(http请求插件),vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐的axios,前一段时间用了一下,现在说一下它的基本用法。配置文件选项,这里的config是对一些基本信息的配置,比如请求头,baseURL,请求方式等等,当然这里提
vue项目实战(一)
Chen_Wei_Sheng的博客
11-29 505
这里是问你的路由模式是否需要选择history模式 如果是就输入Y 如果不是 那就是选择了hash模式 那么就输入n。第一步:找到你想要存放项目的文件夹 输入cmd 就会弹出小黑窗 然后输入vue create 项目名 创建项目。如果你输入Y 就表示你要存储这些设置 下一步就会让你给这些设置取个名字 你下一次就可以直接选择这个了。选择项目设置 按上下键切换 按空格键选择或者取消选择 最终我们选择下面四个 然后回车键。这里是选择Vue.js的版本 我们选择2.X。我们选择hash模式 所以输入n。
vue项目实践(vuex + vue-router + vue-resource)
weixin_34268843的博客
08-29 227
2018.3.1更: 有赞·微商城(base杭州)部门招前端啦,最近的前端hc有十多个,跪求大佬扔简历,我直接进行内推实时反馈进度,有兴趣的邮件 lvdada#youzan.com,或直接微信勾搭我 wsldd225 了解跟多 有赞开源组件库·zanUI 初次接触vue,刷完了堪称经典的vue官网文档+vue-router文档+vuex...
Vue项目实战(博客)
qq_42964711的博客
05-19 253
安装脚手架 安装node.js 安装淘宝镜像npm config set registry https://registry.npm.taobao.org 安装脚手架npm install -g @vue/cli 使用 vue create 项目名 上下加空格和回车 按n选择hash模式路由 选Standard config 都选第一个 最后选n不保存模板 项目结构 C.分析Vue脚手架生成的项目结构 node_modules:依赖包目录 public:静态资源目录 src:
vscode vue项目实战
09-08
综上所述,以上是在VSCode中进行Vue项目实战的一些基本步骤和建议。通过合理利用VSCode的功能和插件,你可以更高效地开发Vue项目。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 实训-利用HTML和CSS制作一个网页界面 30768
  • Vue 项目实战 15267
  • then 方法 7140
  • vue 中编写404页面 5652
  • JS中for循环绑定事件 5474

分类专栏

  • Vue 13篇
  • 开发错误记录 4篇
  • 工作 11篇
  • react 3篇
  • js 35篇
  • flutter 8篇
  • springboot 4篇
  • nodejs 6篇
  • HTML及CSS 11篇
  • JavaScript高级程序设计(第三版)读书笔记 13篇

最新评论

  • 实训-利用HTML和CSS制作一个网页界面

    2301_77469923: up为啥我的都成列排序啊

  • 实训-利用HTML和CSS制作一个网页界面

    李浩东@: 不错,实现响应式的话效果会更好,你这个页面现在还不是响应式页面

  • vue 中编写404页面

    see_dawn.: 为啥照着抄展示的界面不一样啊

  • vue 中编写404页面

    请把小熊还给我&: beforeDestroy() { clearInterval(this.timer) }

  • vue 中编写404页面

    请把小熊还给我&: 清除定时器应该放在销毁方法里而不是点击跳转在销毁

最新文章

  • 在毕设中,使用vue3+pinia的一些收获
  • Git报错 Permission to A/BestoneGitHub.git denied to B
  • React Hooks 与 setInterval
2022年4篇
2021年61篇
2020年38篇

目录

目录

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

深圳SEO优化公司呼和浩特网站优化按天计费青岛seo网站优化推荐咸阳网络推广推荐娄底网站定制推荐黄山网络广告推广价格昌吉至尊标王哪家好长春seo推荐铜川模板推广公司木棉湾SEO按天收费公司贵阳百度爱采购公司武汉优化公司拉萨设计网站公司武威阿里店铺运营哪家好甘孜网站制作报价广州网页设计推荐塘坑seo优化菏泽网站开发推荐江门网站推广系统多少钱云浮网站优化按天收费价格海口SEO按天计费推荐坪地网站设计模板多少钱塔城设计公司网站价格恩施网站优化排名推荐玉林企业网站制作推荐深圳SEO按天扣费公司德阳百度seo上饶网站设计模板价格西乡网站制作哪家好咸阳阿里店铺托管多少钱北海网站建设歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化