Vue项目说明

学什么?

  • 1 如何使用 Vue 开发一个项目
  • 2 ElementUI 组件库的使用
  • 3 业务逻辑(登录、权限、商品)

创建项目

  • 通过 vue-cli 脚手架工具直接生成一个项目
  • 1 创建:vue init webpack shop-admin
  • 2 配置(根据脚手架的引导来选择配置项)
  • 3 cd shop-admin
  • 4 启动项目:npm run devnpm start

手动配置路由

  • 1 安装:npm i vue-router
  • 2 在 src 目录中,新建 router 文件夹,在文件中新建 index.js 路由的配置文件
  • 3 在 index.js 中,配置路由,并导出路由实例
  • 4 在 main.js 中导入 路由配置,并且与 Vue实例 关联到一起
  • 5 在 App.vue 中,添加路由出口

element-ui 组件库的使用

  • 1 安装:npm i element-ui
  • 2 在 main.js 中,导入 element-ui、样式,并安装插件
  • 3 直接在文档中找到对应的组件使用即可

项目接口本地搭建

  • 0 解压 shop-api.zip 文件
  • 1 打开 phpStudy 启动 MySql 服务
  • 2 打开 navicat for mysql 工具,连接数据库
  • 3 在链接上,点右键新建数据库,数据库名称为:shop_admin
  • 4 双击启用数据库,再右键 运行SQL文件,选中 shop_admin.sql,并导入
  • 5 打开 shop-api 目录,修改 config/default.json 中的数据库用户名和密码(如果需要)
  • 6 在 shop-api 目录中,打开终端,输入:npm start 启动接口服务

以后每天写项目之前要做的事情

  • 1 开启 phpStudy 中的 MySql 服务
  • 2 在 shop-api 目录中,执行 npm start 启动接口服务

使用 git 管理项目

# 原始提交到远程仓库的命令
git push https://gitee.com/zqran/shop_admin_31.git master
# 有了 remote 后:
git push shop master
# 使用 -u 命令后:
git push shop

# 将 仓库地址 与 shop 这个名称关联到一起
git remote add shop https://gitee.com/zqran/shop_admin_31.git

# -u 就是将 master 设置为默认,提交的时候,就不需要每次都指定 master 分支了
# -u 命令只需要执行一次即可
git push -u shop master

登录功能

搭建登录表单结构

  • 1 到 element-ui 文档中找到 表单组件
  • 2 找到合适的组件,点击显示代码,将 文档中提供的 示例代码拷贝到我们自己的 Login.vue 组件中
    • 目的:为了让这个组件能够在项目中先正常运行起来
  • 3 分析 组件结构
    • 先从整体分析这个结构
  • 4 修改这个结构,让其变为适合我们功能的结构

登录逻辑

调整登录组件的样式

ref

  • 作用:添加给 DOM元素或组件,将来可以通过 this.$refs.ref的值 来获取到这个DOM对象或组件。然后,就可以进行DOM操作或获取组件数据、调用组件方法了

编程式导航 - JS代码实现路由跳转功能

  • this.$router.push('/home')
    • 参数 /home:表示要跳转到的路由地址
  • this.$router.push({ name: 'home' })
    • 通过 name 属性来实现路由跳转

element-ui 消息提示组件

// 这是 element-ui 中提供的一个方法,用来做消息提示:

this.$message({
  // 提示信息
  message: res.data.meta.msg,
  // 消息提示的类型
  type: 'error',
  // 表示消息显示时长
  duration: 1000
})

登录访问控制

  • 1 如果没有登录,只能访问登录页面,而不能访问其他
  • 2 如果没有登录,访问其他页面,应该跳回到登录页面
  • 3 如果登录了,就可以访问其他页面了

如何知道有没有登录

  • 1 Vue项目使用 token 来作为登录成功的标识

    • 只要有 token 就说明已经登录了
    • 如果没有 token 就说明还没有登录
  • 2 原来,通过 sessionid + cookie 机制,来实现登录状态保持

    • 将 sessionid 存储到 cookie 中,这样,登录状态标识(sessionid),就会随着每一次请求都发送给服务器,服务器从 cookie 中获取到sessionid,就知道是否登录过了
  • 这两种不同机制都是为了解决同一个问题: 登录状态保持

    • 为什么需要状态保持? 因为 HTTP 协议是无状态的
  • 现在,登录成功后,需要将 token 保存起来,存储到 localStorage 中,其他地方用到了,就直接从 localStorage 中取出来使用就可以了

样式调整

  • 哪个组件的结构,就把样式放在哪个组件的 style 标签中

菜单组件结构分析

<!--
  el-menu 菜单组件
    default-active="2" 设置默认菜单高亮,值是el-menu-item的index值
    @open="handleOpen"    菜单展开事件
    @close="handleClose"  菜单收起事件
    background-color="#545c64" 菜单背景色
    text-color="#fff" 菜单文字颜色
    active-text-color="#ffd04b" 菜单高亮文字颜色
  el-submenu 二级菜单,也就是一个可以展开收起的组件。
    这个组件可以嵌套,形成多级菜单
    index="1" 唯一标志,可以用来设置菜单高亮
  el-menu-item 可点击的菜单项组件
    disabled 表示禁用这个菜单
-->
<el-menu
  default-active="4"
  background-color="#545c64"
  text-color="#fff"
  active-text-color="#ffd04b"
>
  <el-submenu index="1">
    <template slot="title">
      <!-- 指定了菜单的图标 -->
      <i class="el-icon-location"></i>
      <!-- 指定了菜单名称 -->
      <span>导航一</span>
    </template>
    <!-- 分组菜单: -->
    <el-menu-item-group>
      <template slot="title">分组一</template>
      <el-menu-item index="1-1">选项1</el-menu-item>
      <el-menu-item index="1-2">选项2</el-menu-item>
    </el-menu-item-group>
    <el-menu-item-group title="分组2">
      <el-menu-item index="1-3">选项3</el-menu-item>
    </el-menu-item-group>
    <el-submenu index="1-4">
      <template slot="title">选项4</template>
      <el-menu-item index="1-4-1">选项1</el-menu-item>
    </el-submenu>
  </el-submenu>
  <el-menu-item index="2">
    <i class="el-icon-menu"></i>
    <span slot="title">导航二</span>
  </el-menu-item>
  <el-menu-item index="3" disabled>
    <i class="el-icon-document"></i>
    <span slot="title">导航三</span>
  </el-menu-item>
  <el-menu-item index="4">
    <i class="el-icon-setting"></i>
    <span slot="title">导航四</span>
  </el-menu-item>
</el-menu>

props类型的说明

  • :router="true" 此时,router 的值是 布尔值 类型的
    • 设置为字符串类型::router=" 'true' "
    • 设置为数值类型::router="123"
  • router="true" 此时,router的值是 字符串 类型的

嵌套路由使用步骤

  • 1 在创建路由规则的时候,要配置子路由规则,而不是普通的路由
    • 子路由是通过路由中的 children 属性来配置的
  • 2 在需要切换内容的组件中,添加一个子路由的出口
    • <router-view />

接口使用说明

  • 注意:除了登录接口意外,其他所有的接口都需要将 token 传递给服务器,这样,服务器才知道用户有没有登录
  • 如何传递 token ?
    • 在 header 中添加 Authorization 请求头

用户列表功能

获取用户列表数据

  • 1 在 data 配置中,添加数据 userList: []
  • 2 在 created 钩子函数中,发送请求,获取用户列表数据
    • 根据接口文档,找到接口和需要的参数
  • 3 将接口返回的数据交给 userList
  • 4 修改 el-table 表格组件中的 prop 属性,使其与接口返回的数据匹配

分页获取数据

  • 0 封装 分页获取数据 方法
  • 1 给组件绑定 @current-change 事件
  • 2 通过事件参数获取到当前页码
  • 3 在事件中,调用封装好的方法,获取当前页数据

退出功能

  • 1 给 退出 按钮绑定单击事件
  • 2 在事件中调用 element-ui 的弹框组件,弹出一个确认对话框
  • 3 在用户点击 确定 按钮的时候,执行 退出 功能
    • 3.1 返回到登录页面
    • 3.2 从 localStorage 中移除token

项目中的作用域插槽使用

  • 如果想要获取表格中的数据,就通过 slot-scope 的值 scope.row 来获取
<template slot-scope="scope">
  <!--
    scope.row 表示当前行数据
    mg_state 就是当前用户的状态
  -->
  <el-switch v-model="scope.row.mg_state"></el-switch>
</template>

切换用户状态功能

  • 1 给 开关组件 绑定 change 事件
  • 2 在事件中获取到当前用户的状态
  • 3 将状态发送接口,来完成切换用户状态功能

优化axios的使用

  • 1 每次发送请求的时候,都要拷贝完整的基准地址
    • 期望:配置基准地址,在发送请求的时候,只需要填写当前接口地址
// 配置基准路径:
axios.defaults.baseURL = 'http://localhost:8888/api/private/v1'
  • 2 每次发送请求的时候,都需要设置一次请求头
    • 期望:配置请求头,在发送请求的时候,就不需要每次都单独设置请求头
// 请求拦截器
// 说明:因为只要是 axios 发送的请求,都会执行 请求拦截器 中的代码
//      所以,可以在 请求拦截器 中, 一次性添加请求头
axios.interceptors.request.use(config => {
  // 统一添加 Authorization 请求头
  config.headers.Authorization = localStorage.getItem('token')
  // 一定要返回 config
  return config
})
  • 3 每个组件中都要单独导入axios
    • 期望:导入一次,而不是每个组件中都单独导入
// main.js

import axios from 'axios'
Vue.prototype.$http = axios

用户列表 - 查询

  • 1 从 element-ui 中找到搜索组件
  • 2 给搜索按钮绑定单击事件
  • 3 在事件中获取到文本框中输入的搜索内容
  • 4 根据搜索内容,调用查询接口,查询数据
  • 注意:新功能对老功能的影响,也就是说:添加了一个新的功能进来,实现后,要自己测试一下有没有对老的功能产生影响

用户列表 - 删除

  • 1 给删除按钮绑定单击事件,并且传递 id 参数
  • 2 事件中弹出确认对话框,防止用户误操作
  • 3 当用户点击确定的时候,根据id调用接口删除用户
  • 4 删除成功后,重新获取用户列表数据

用户列表 - 添加用户

  • 1 给添加用户按钮,绑定单击事件
  • 2 在事件中,弹出一个对话框
  • 3 进行表单结构、数据、验证的处理
  • 4 给 确定 按钮绑定单击事件,来进行表单验证,验证成功后,再添加用户
  • 5 添加成功后,关闭对话框,重新刷新列表数据
  • 关闭对话框的时候,要重置表单(1 数据 2 校验状态)
    • 给对话框绑定关闭事件 close
    • 在事件中,重置表单

表单验证的说明

  • element-ui 中的表单验证规则,依赖于:async-validator
  • 具体的验证规则,应该从这个库中查找

使用组件的注意点

  • 1 首先想到的是 组件自身 有没有提供对应的功能
  • 2 查看文档,看有没有对应的功能
  • 3 如果提供了,就直接使用提供的方式即可
  • 4 如果没有提供,就自己实现

用户列表 - 编辑

  • 1 给编辑按钮绑定单击事件
  • 2 在单击事件中,弹出对话框
  • 3 获取到当前用户数据,并且展示在 编辑对话框 中
  • 4 给 确定 按钮,绑定单击事件
  • 5 获取当前用户数据,发送请求,修改数据
  • 6 修改成功后,关闭对话框、提示用户编辑用户成功、刷新列表数据

抽离组件为三部分

  • 注意:三个部分的文件名称可以是任意的
<!-- 三个内容中,都是通过 src 属性,引用内容的 -->
<template src="./template.html"></template>
<script src="./script.js"></script>
<style src="./style.css"></style>

<!-- 如果要使用 less 这样配置: -->
<!-- 1 -->
<style src="./style.less" lang="less"></style>
<!-- 2 安装: npm i -D less less-loader -->

VScode 生成SFC模板

// vue 文件中:

{
  "vue SFC": {
    "prefix": "vuetss",
    "body": [
      "<template src=\"./template.html\"></template>",
      "<script src=\"./script.js\"></script>",
      "<style lang=\"less\" src=\"./style.less\"></style>",
      ""
    ],
    "description": "快速生成单文件组件分离后的结构"
  }
}

权限模块 - 业务逻辑

  • 权限模块的组成: 权限、角色、用户

  • 权限和角色的关系:每个角色都有自己的权限,权限是属于角色的

    • 一个权限可以属于多个角色,一个角色可以有多个权限
    • 权限 和 角色的关系:多对多
  • 角色和用户的关系:每个用户只能有一个角色,一个角色可以属于多个用户

    • 角色 和 用户:一对多
  • 权限 和 用户,间接的就有关系了,因为 权限和角色 是有关系的,角色和用户也是由关系的,所以,权限 和 用户,间接的就有了关系

  • 问题:如何给用户分配权限???

    • 1 给用户分配角色
    • 2 给角色分配权限
    • 3 这样,只要用户有某个角色,那么,他就拥有了这个角色下面的所有权限
  • 比如:

    • 用户:test5,他的角色是:产品经理
    • 产品经理这个角色拥有的权限:商品管理订单管理权限管理

权限和菜单

  • 权限和菜单也是关联在一起的
  • 也就是说:有什么权限,就有什么菜单
  • 权限是有三级的,但是菜单只有两级。因为 三级权限 就是具体的 CRUD 功能了

总结

  • 权限模块中的4个内容: 菜单、权限、角色、用户
  • 一个用户登录系统后,这个用户是由自己的角色的,角色又有自己的权限,权限又关联到了具体的菜单
  • 实现权限模块功能的时候,要做的事情:
    • 1 给角色分配权限
    • 2 给用户分配角色

角色列表

  • 1 从文档中找到表格组件
  • 2 拷贝到项目中,先跑起来
  • 3 修改 表格组件 ,改为我们要用的功能

分析用户拥有的权限数据结构

  • tree 树形结构,类似于 DOM 树
children: [
  // 权限名称
  roleName: '一级权限',
  // 二级权限列表
  children: [
    {
      roleName: '二级权限 1',
      // 三级权限列表:
      children: []
    },
    {
      roleName: '二级权限 2',
      // 三级权限列表:
      children: []
    }
 ]
]

给角色分配权限

  • 1 先给 分配权限 按钮绑定单击事件
  • 2 在事件中先弹出一个对话框
  • 3 从 文档 中找到 树形组件 ,拷贝到项目中,先跑起来
  • 4 分析结构
  • 5 进入页面时,发送请求,获取权限列表的树形结构数据,并渲染到 tree 中
  • 6 给 确定按钮 绑定单击事件
  • 7 在事件中,获取到选中所有节点id
  • 8 发送请求,完成给角色授权

Vue组件样式的问题说明

  • 注意:组件中的样式应该只对当前组件生效,而不是要对其他组件产生影响!!!
  • 如果产生影响,会到组件之间的样式冲突、覆盖等问题
  • Vue 中提供了一个属性 scoped,只要给 组件的style标签 添加这个属性,那么,样式就只会对当前组件生效,而不会影响其他组件
  • 所以,推荐在使用组件的时候,给 style 标签,添加 scoped 属性!!!
  • scoped 原理:动态给组件中的标签添加一个 data-v-组件唯一标识 属性,并且样式中自动添加了属性选择器。因为每个组件的 唯一标识 是不一样的,所以,样式就只会对当前组件生效了

element-tree-grid

  • 1 安装:npm i element-tree-grid("element-tree-grid": "^0.1.3")
  • 2 在 main.js 中,注册全局组件:
import ElTreeGrid from 'element-tree-grid'
Vue.component(ElTreeGrid.name, ElTreeGrid)
<!--
  label :设置列名称
  prop :提供列内容的属性名

  tree-key :区分其他菜单,不添加该key会导致所有菜单同时展开,添加该key只展开该菜单
  level-key :设置菜单级别,以缩进形式表示子菜单
  parent-key :父级菜单id,不添加该key,则无法收起子菜单
  child-key :指定使用哪个属性名称表示子菜单,默认值为:children
-->

<el-table-tree-column
  tree-key="cat_id"
  level-key="cat_level"
  child-key="children"
  parent-key="cat_pid"
  label="分类名称"
  prop="cat_name"
  width="320"
  :indent-size="20"
>
  <template slot-scope="scope">
    <span>{{ scope.row.cat_name }}</span>
  </template>
</el-table-tree-column>

富文本编辑器

  • vue-quill-editor
  • 1 安装: npm i vue-quill-editor
  • 2 在当前组件中导入, 注册为局部组件并使用
// 导入样式文件:
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

import { quillEditor } from 'vue-quill-editor'

export default {
  components: {
    quillEditor
  }
}
<quill-editor v-model="goodsAddForm.goods_introduce"></quill-editor>

动态获取菜单

  • 菜单是动态获取的,不同的用户有不同的角色,不同的角色有不同的权限,每个权限都对应到了菜单
  • 所以,不同的用户能够看到不同的菜单
  • 问题:不管哪个用户都是通过 /menus 这个接口来获取菜单数据的,没有传id,但是,服务器返回的数据不一样,服务器是如何区分不同用户的?
    • 根据 token ,token中是包含了用户身份信息的

加载中效果

  • 说明: element-ui 中提供了一个 自定义指令 v-loading 这个指令用来添加 loading 效果
  • 使用: 想要哪个组件(那块区域出现)加载中效果,就给哪个组件添加自定义指令 v-loading 即可
<!-- 
  loading 是一个布尔值数据,如果为true表示展示加载中效果;如果为false,表示隐藏加载中效果
-->
<el-table v-loading="loading"></el-table>

添加分类

  • 1 给添加分类按钮绑定单击事件,在事件中弹出对话框
  • 2 从 elemenet-ui 组件库中拷贝对话框组件到项目中,跑起来
  • 3 分析 级联选择器 结构
  • 4 获取 级联选择器 中的所有分类数据( created 钩子函数中获取 )
  • 5 获取 级联选择器 中选择项的值(id)
  • 6 给 确定 按钮绑定单击事件,在事件中获取到接口需要的数据
  • 7 发送请求,完成添加分类功能

商品列表

  • 实现 路由版的分页 功能
  • 1 刷新页面的时候,路由中显示的是第几页,就要获取到这一页的数据
    • 1.1 如何在刷新页面的时候,从路由中获取当前页(路由参数)?
    • 1.2 因为是在刷新页面的时候获取,因此,需要在 created 钩子函数中
    • 1.3 通过 this.$route.params.page 获取到当前路由参数(页码)
  • 2 切换分页的时候,要改变路由中的路由参数(页码)
    • 2.1 要改变哈希值就直接调用 this.router.push(`/goods/{curPage}`)

样式 scoped 属性的问题说明

  • 注意:添加 scoped 属性后,样式只对组件内部的结构生效。对于动态生成的结构无效!!!
  • 结论:
    • 1 推荐在使用style给组件添加样式的时候,使用 scoped 属性
    • 2 如果发现在 scoped 添加的样式无效,此时,有可能就是动态生成结构的问题,此时,就去掉 scoped 属性,来看下样式是否生效
    • 3 如果生效了,就说明是动态生成元素的问题,此时,就创建一个新的 style 标签并且不添加scoped属性,将动态生成元素的样式放在这个style标签中
    • 4 如果不生效,则可能是 类名 错了等问题~

项目打包和优化

  • 打包命令:npm run build

优化:按需加载

  • 说明:基于 webpack 的代码分离 和 Vue异步组件
  • 1 修改 router/index.js 中导入组件的语法
// 使用:
const Home = () => import('@/components/home/Home')
// 替换:
// import Home from '@/components/home/Home'

// 给打包生产的JS文件起名字
const Home = () =>
  import(/* webpackChunkName: 'home' */ '@/components/home/Home')

// chunkName相同,将 goods 和 goods-add 两个组件,打包到一起
const Goods = () => import(/* webpackChunkName: 'goods' */ '@/components/goods')
const GoodsAdd = () =>
  import(/* webpackChunkName: 'goods' */ '@/components/goods-add')
  • 2 (该步可省略)修改 /build/webpack.prod.conf.js 中的 chunkFilename
{
  // [name] 代替 [id]
  chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')
}

优化:使用CDN

项目中使用CDN

  • 问题:打包后 vendor(第三方资源文件) 体积过大
  • 原因:项目中用到了很多的第三方包,这些包在打包的过程中,全部打包到了 vendor 这个一个JS文件中,导致体积过大
  • 如何优化 vendor 体积? 使用CDN
  • 原理:使用CDN处理第三方包,是引用的在线地址。此时,这些包不会被打包到 vendor 文件中,因此,vendor 体积就会变的更小

CDN使用步骤

  • 1 在 index.html 中引入 CDN 提供的 JS 文件

  • 2 在 /build/webpack.base.conf.js 中(resolve 前面)添加配置 externals

  • 注意:通过 CDN 引入 element-ui 的样式文件后,就不需要在 main.js 中导入 element-ui 的 CSS 文件了。所以,直接注释掉 main.js 中的导入 element-ui 样式即可

  • externals配置:

externals: {
  // 键:表示 导入包语法 from 后面跟着的名称
  // 值:表示 script 引入JS文件时,在全局环境中的变量名称
  //  window.Vue / window.axios / window.VueRouter
  vue: 'Vue',
  axios: 'axios',
  'vue-router': 'VueRouter',
  // 注意:带有样式文件的第三方包,需要在 代码中 将样式注释掉!!!
  'element-ui': 'ELEMENT',
  'element-tree-grid': 'ElTableTreeColumn',
  'vue-quill-editor': 'VueQuillEditor'

  BMap: 'BMap',
  echarts: 'echarts',
}

常用包 CDN

Quill

<!-- Include the Quill library -->
<script src="https://cdn.bootcss.com/quill/1.3.4/quill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script>

<!-- Include stylesheet -->
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.core.min.css" rel="stylesheet"/>
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.snow.min.css" rel="stylesheet"/>
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.bubble.min.css" rel="stylesheet"/>

缓存和保留组件状态

  • keep-alive
  • 解决方式:使用 keep-alive ,步骤如下:
1 在需要被缓存组件的路由中添加 meta 属性 meta
属性用来给路由添加一些元信息(其实,就是一些附加信息)
{
  path: '/',
  name: 'home',
  component: Home,
  // 需要被缓存
  meta: { keepAlive: true }
}

2 修改路由出口,替换为以下形式: 根据 meta 是否有 keepAlive
属性,决定该路由是否被缓存
<keep-alive>
  <!-- 这里是会被缓存的视图组件 -->
  <router-view v-if="$route.meta.keepAlive"> </router-view>
</keep-alive>

<!-- 这里是不被缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"> </router-view>

启用路由的 History 模式

  • 通过在路由中添加 mode: 'history' 可以去掉 浏览器地址栏中的 #
  • 在开发期间,只需要添加这个配置即可
  • 但是,在项目打包以后,就会出现问题
// 去掉 # 后,地址变为: http://localhost:8080/goods 那么,服务器需要正确处理
/goods 才能正确的响应内容, 但是,/goods 不是服务端的接口,而是
用来在浏览器中实现 VueRouter 路由功能的

后端的处理方式

  • 1 优先处理静态资源
  • 2 对于非静态资源的请求,全部统一处理返回 index.html
  • 3 当浏览器打开 index.html 就会加载 路由的 js 文件,那么路由就会解析 URL 中的 /login 这种去掉#的路径了

反向代理

proxyTable: {
  // 使用:/api/movie/in_theaters
  // 访问 ‘/api/movie/in_theaters’ ==> 'https://api.douban.com/v2/movie/in_theaters'
  '/api': {
    // 代理的目标服务器地址
    target: 'https://api.douban.com/v2',
    // https请求需要该设置
    secure: false,
    // 必须设置该项
    changeOrigin: true,
    // '/api/movie/in_theaters' 路径重写为:'/movie/in_theaters'
    pathRewrite: {"^/api" : ""}
  }
}

Vuex

推荐阅读更多精彩内容

  • 目录 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element★13489 ...
    余生社会阅读 18,115评论 7 233
  • 打卡1:晚上在公交车上,一名微醉酒男士骂了司机,司机憋着一肚子气,我真想说点什么去安慰一下司机,正好这之后不一会儿...
    吴宁归一阅读 57评论 0 0
  • 流血流泪不怕,但最起码要流老板血老板泪。
    墨无文阅读 24评论 0 0
  • 在现在这个社会中有太多的人对未来的道路感到迷茫,但是在通往未来的道路上一定是充满荆棘的你只有不停的往前跑才会...
    NULRIY阅读 191评论 0 1
  • 好雨知时节,当春乃发生。随风潜入夜,润物细无声。野径云俱黑,江船火独明。晓看红湿处,花重锦官城。
    丹丘生_9115阅读 586评论 4 25