2023-12-04学习笔记(用Vue框架创建一个新的项目)通过学习《Vue 大事件》项目,巩固 Vue 基础中所学的知识,掌握从 0 到 1 开发企业级项目的能力。

初始化-注册-登录

01.项目-简介

目标

  • 通过学习《Vue 大事件》项目,巩固 Vue 基础中所学的知识,掌握从 0 到 1 开发企业级项目的能力。

讲解

所需的前置知识

  1. Vue 基础
    vue-cli、指令、组件、vue-router路由、vuex
  2. axios
    baseURL、拦截器
    element-ui
  3. 安装与配置、常用的组件
    npm 与 模块化

安装两个软件

vscodenode
检测node安装是否成功
打开终端输入以下命令

node -v
npm -v
  • 能使用 npm 维护项目中的依赖包
  • ES6 模块化语法

学完本项目可以掌握的能力

  1. 登录注册的业务实现流程
  2. 在项目中使用 vuex 管理全局共享的数据
  3. element-ui 组件在实际开发中的应用
  4. 文件上传、富文本编辑器在 Vue 项目中的应用

小结

我们为何要做这个项目?
为了练习我们的Vue基础掌握的知识, 学习更多的业务和项目场景

02.项目-初始化

目标

  • 从0创建1个Vue脚手架模板项目, 自带路由和vuex以及eslint等

讲解

  1. 确认自己vue命令版本
  • 查看vue命令版本(注意: 是大V)
vue -V
  • 安装vue脚手架
npm i @vue/cli -g
  1. 初始化项目
    注意:项目的名字不能用中文
vue create 项目的名字

键盘上下箭头,选择第二个 vue2,按下回车,创建项目。

  1. 启动项目
npm run serve
  1. 安装插件
    在package.json文件内,dependenciesdevDependencies追加以下内容
"dependencies": {
    "vue-quill-editor": "^3.0.6",
    "dayjs": "^1.11.3",
    "echarts": "^5.3.2",
    "vue-router": "^3.5.1",
    "vuex": "^3.6.2",
    "vuex-persistedstate": "3.2.1"
  },
  "devDependencies": {
    "less": "^4.0.0",
    "less-loader": "^8.0.0"
  },
  1. 下载插件
npm i
  1. 梳理项目结构

为项目开发做准备,把不需要的代码、文件删除掉

a. 重置src/App.vue组件中的代码

<template>
  <div>App 根组件</div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style lang="less" scoped></style>

b. 新建 src/router/index.js 路由模块中的代码

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
  routes
})

export default router

c. 清空 src/components 目录。
d. 把图片素材目录下的 images 文件夹(项目中需要用到的图片),复制粘贴到 src/assets 目录下。
e. 并把global.less, 引入到main.js

import '@/assets/global.less' // 全局初始化样式

小结

  1. 初始化模板都有什么功能?

得到一个脚手架基础环境, 有babel, vue-router和vuex, 以及支持vue语法和vue文件开发的webpack0配置环境

03.项目-配置组件库

目标

  • 项目配置element-ui全部注册, 提高页面开发效率

讲解

参照 element-ui 的官方文档,进行安装、配置、使用:https://element.eleme.io/#/zh-CN/component/installation

  1. 下载element-ui包到当前项目(注意它支持的是Vue2版本项目)
npm i element-ui
  1. 找到src/main.js, 在这里进行组件引入和注册
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

小结

  1. 为何elementUI注册单独封装个模块文件?
    分散管理, 方便查找

04.项目-封装请求库

目标

  • 封装项目请求架构, 为后面请求数据做准备
    讲解
    核心思想: 分层架构

  • 在任意组件, 调用封装的接口方法, 接口方法调用统一的axios函数告诉他请求的参数, 它去请求数据

我(任意页面) -> 秘书(接口函数) -> 车(axios) -> 数据(后台返回)

  1. 安装 axios
npm i axios
  1. 新建src/utils/request.js项目核心请求方法的模块文件
import axios from 'axios'

// 创建一个自定的axios方法(比原axios多了个基地址)
// axios函数请求的url地址前面会被拼接基地址, 然后axios请求baseURL+url后台完整地址
const myAxios = axios.create({
  baseURL: 'http://big-event-vue-api-t.itheima.net'
})

// 导出自定义的axios方法, 供外面调用传参发请求
export default myAxios
  1. 新建src/api/index.js项目接口方法统一管理模块文件
import request from '@/utils/request'

export const getListAPI = () => {
  // 这里先用这个接口测试下, 如果url以http开头会忽略baseURL, axios直接请求此地址
  return request({
    url: 'http://geek.itheima.net/v1_0/channels'
  })
}
  1. 在任意组件src/App.vue中, 引入接口请求方法, 并请求数据
import { getListAPI } from '@/api'
export default {
  created () {
    this.getListFn()
  },
  methods: {
    async getListFn () {
      const res = await getListAPI()
      console.log(res)
    }
  }
}

这种分层架构思想, 可以更好的统一管理项目中所有接口, 并也方便统一给axios方法添加拦截器和修改基地址

小结

  1. 为何要把网络请求封层, 分文件模块来管理?
    便于管理和查找, 以及替换和修改
  2. 网络请求, 封装了哪些东西?
    utils/request.js网络请求工具函数, api/index.js定义具体请求的接口方法和传参, 在任意组件调用接口方法请求拿到数据

05.项目-注册和登录-页面准备

目标

● 准备注册和登录页面组件及路由

讲解

  1. 新建注册页面组件, 在src/views/register/index.vue, 直接复制标签
<template>
  <div>
    Reg.vue
  </div>
</template>

<script>
export default {
  name: 'my-register'
}
</script>

<style lang="less" scoped></style>
  1. 新建登录页面组件, 在src/views/login/index.vue, 直接复制标签
<template>
  <div>
    Login.vue
  </div>
</template>

<script>
export default {
  name: 'my-login'
}
</script>

<style lang="less" scoped></style>
  1. src/router/index.js配置路由表
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/reg',
    component: () => import('@/views/register')
  },
  {
    path: '/login',
    component: () => import('@/views/login')
  }
]

const router = new VueRouter({
  routes
})

export default router
  1. App.vue组件中,定义<router-view>如下

可以把之前测试的代码直接覆盖掉

<template>
 <router-view></router-view>
</template>

<script>
export default {
 name: 'App'
}
</script>

<style lang="less" scoped></style>

5. 启动webpack开发服务器, 然后在页面的地址栏, 手动切换路由地址看是否配置成功

小结

路由表是什么?
指的路由规则对象的数组, 路由对象是路径和组件的映射关系

06.注册-标签布局和表单校验

目标

  • 完成注册页面, 标签和样式布局

讲解

  1. src/views/register/index.vue, 初始化注册页面的基础布局,并美化样式, 先看需求图, 分析后直接复制后阅读
<template>
  <!-- 注册页面的整体盒子 -->
  <div class="reg-container">
    <!-- 注册的盒子 -->
    <div class="reg-box">
      <!-- 标题的盒子 -->
      <div class="title-box"></div>
      <!-- 注册的表单区域 -->
    </div>
  </div>
</template>

<script>
export default {
  name: 'my-register'
}
</script>

<style lang="less" scoped>
.reg-container {
  background: url('../../assets/images/login_bg.jpg') center;
  background-size: cover;
  height: 100%;

  .reg-box {
    width: 400px;
    height: 335px;
    background-color: #fff;
    border-radius: 3px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 0 30px;
    box-sizing: border-box;

    .title-box {
      height: 60px;
      background: url('../../assets/images/login_title.png') center no-repeat;
    }

    .btn-reg {
      width: 100%;
    }
  }
}
</style>
  1. 查找elementUI组件库, 要完成表单组件布局, 并带上基础校验,自己分析铺设, 变量可以看, 不可以复制
  • 规则1: 用户名必须是1-10的大小写字母数字
  • 规则2: 密码必须是6-15的非空字符
  • 规则3: 确认密码必须和密码值一致
<!-- 注册的表单区域 -->
<el-form :model="regForm" :rules="regRules" ref="regRef">
  <!-- 用户名 -->
  <el-form-item prop="username">
    <el-input v-model="regForm.username" placeholder="请输入用户名"></el-input>
  </el-form-item>
  <!-- 密码 -->
  <el-form-item prop="password">
    <el-input v-model="regForm.password" type="password" placeholder="请输入密码"></el-input>
  </el-form-item>
  <!-- 确认密码 -->
  <el-form-item prop="repassword">
    <el-input v-model="regForm.repassword" type="password" placeholder="请再次确认密码"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" class="btn-reg">注册</el-button>
    <el-link type="info">去登录</el-link>
  </el-form-item>
</el-form>


<script>
export default {
  name: 'my-register',
  data () {
    const samePwd = (rule, value, callback) => {
      if (value !== this.regForm.password) {
        // 如果验证失败,则调用 回调函数时,指定一个 Error 对象。
        callback(new Error('两次输入的密码不一致!'))
      } else {
        // 如果验证成功,则直接调用 callback 回调函数即可。
        callback()
      }
    }
    return {
      // 注册表单的数据对象
      regForm: {
        username: '',
        password: '',
        repassword: ''
      },
      // 注册表单的验证规则对象
      regRules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          {
            pattern: /^[a-zA-Z0-9]{1,10}$/,
            message: '用户名必须是1-10的大小写字母数字',
            trigger: 'blur'
          }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          {
            pattern: /^\S{6,15}$/,
            message: '密码必须是6-15的非空字符',
            trigger: 'blur'
          }
        ],
        repassword: [
          { required: true, message: '请再次输入密码', trigger: 'blur' },
          { pattern: /^\S{6,15}$/, message: '密码必须是6-15的非空字符', trigger: 'blur' },
          { validator: samePwd, trigger: 'blur' }
        ]
      }
    }
  }
}
</script>

小结

写任何需求的套路是什么?
先准备标签和样式, 然后准备数据/变量绑定/校验规则设置

  1. 注册-功能实现

目标

● 完成点击注册按钮校验和注册功能

讲解

核心思想: 注册就是把用户输入的账号和密码做好校验以后, 收集到变量中, 再调用接口发给后台, 后台代码把他们存储到数据库中, 再给前端返回提示

  1. 注册按钮, 绑定点击事件
<el-button type="primary" class="btn-reg" @click="regNewUserFn">注册</el-button>
  1. 在事件处理函数中, 先执行表单校验
methods: {
    // 注册新用户
    regNewUserFn () {
      // 进行表单预验证
      this.$refs.regRef.validate(valid => {
        if (!valid) return false
        // 尝试拿到用户输入的内容
        console.log(this.regForm)
      })
    }
  }
  1. 前端准备好了, 准备调用后台接口了, 所以准备接口方法, 在src/api/index.js定义
/**
 * 注册接口
 * @param {*} param0 { username: 用户名, password: 密码 }
 * @returns Promise对象
 */
export const registerAPI = ({ username, password, repassword }) => {
  return request({
    url: '/api/reg',
    method: 'post',
    data: {
      username,
      password,
      repassword
    }
  })
}
  1. 在逻辑页面引用接口, 并在注册逻辑中调用, 并使用element绑定在Vue全局属性上的$message弹窗方法
// 注册新用户
regNewUserFn () {
    // 进行表单预验证
    this.$refs.regRef.validate(async valid => {
        if (!valid) return false
        // 尝试拿到用户输入的内容
        // console.log(this.regForm)
        // 1. 调用注册接口
        const { data: res } = await registerAPI(this.regForm)
        console.log(res)
        // 2. 注册失败,提示用户
        if (res.code !== 0) return this.$message.error(res.message)
        // 3. 注册成功,提示用户
        this.$message.success(res.message)
        // 4. 跳转到登录页面
        this.$router.push('/login')
    })
}

小结

  1. 注册的业务逻辑是什么?
    把前端标签准备好, 数据绑定好, 在点击事件中走完表单验证逻辑, 调用接口传参给后台, 根据后台返回的code做前端页面结果提示

08.登录-标签布局和表单校验

目标

在login页面根据需求准备页面标签和样式

讲解

  1. 和注册页面差不多, 标签和校验一样, 在src/views/login/index.vue中, 复制如下标签并阅读核对
<template>
  <!-- 登录页面的整体盒子 -->
  <div class="login-container">
    <!-- 登录的盒子 -->
    <div class="login-box">
      <!-- 标题的盒子 -->
      <div class="title-box"></div>
      <!-- 登录的表单区域 -->
      <el-form :model="loginForm" :rules="loginRules" ref="loginRef">
        <!-- 用户名 -->
        <el-form-item prop="username">
          <el-input v-model="loginForm.username" placeholder="请输入用户名" maxlength="10" minlength="1"></el-input>
        </el-form-item>
        <!-- 密码 -->
        <el-form-item prop="password">
          <el-input
            v-model="loginForm.password"
            type="password"
            placeholder="请输入密码"
            maxlength="15"
            minlength="6"
          ></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" class="btn-login">登录</el-button>
          <el-link type="info">去注册</el-link>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  name: 'my-login',
  data () {
    return {
      // 登录表单的数据对象
      loginForm: {
        username: '',
        password: ''
      },
      // 登录表单的验证规则对象
      loginRules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          { pattern: /^[a-zA-Z0-9]{1,10}$/, message: '用户名必须是1-10的字母数字', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          { pattern: /^\S{6,15}$/, message: '密码必须是6-15的非空字符', trigger: 'blur' }
        ]
      }
    }
  }
}
</script>

<style lang="less" scoped>
.login-container {
  background: url('../../assets/images/login_bg.jpg') center;
  background-size: cover;
  height: 100%;

  .login-box {
    width: 400px;
    height: 270px;
    background-color: #fff;
    border-radius: 3px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 0 30px;
    box-sizing: border-box;

    .title-box {
      height: 60px;
      background: url('../../assets/images/login_title.png') center no-repeat;
    }

    .btn-login {
      width: 100%;
    }
  }
}
</style>
  1. 实现注册页面, 点击去登录跳转效果, 在src/views/register/index.vue中, 找到对应标签绑定点击事件跳转路由页面
<el-link type="info" @click="$router.push('/login')">去登录</el-link>
  1. 实现登录页面, 点击去注册跳转效果, 在src/views/login/index.vue中, 找到对应标签点击中跳转路由
<el-link type="info" @click="$router.push('/reg')">去注册</el-link>

小结

登录和注册如何做的, 核心思想?
用的是2个页面, 做的切换, 其实也可以做标签的显示隐藏, 都能实现
09.登录-功能实现

目标

点击登录按钮, 实现登录逻辑

讲解

核心思想: 通过表单校验, 收集用户输入内容, 调用接口带给后台验证, 返回响应结果, 前端给用户提示结果

  1. 为登录按钮绑定点击事件处理函数如下
<el-button type="primary" class="btn-login" @click="loginFn">登录</el-button>
  1. 先封装要调用的登录接口, 在src/api/index.js
/**
 * 登录接口
 * @param {*} param0 { username: 用户名, password: 密码 }
 * @returns Promise对象
 */
export const loginAPI = ({ username, password }) => {
  return request({
    url: '/api/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}
  1. src/view/login/index.vue登录页面, 引入接口方法并, 实现对应事件处理函数逻辑, 校验和调用接口
methods: {
    // 登录按钮->点击事件
    async loginFn () {
      this.$refs.loginRef.validate(async valid => {
        if (!valid) return
        // 1. 发起登录的请求
        const { data: res } = await loginAPI(this.loginForm)
        // 2. 登录失败
        if (res.code !== 0) return this.$message.error(res.message)
        // 3. 登录成功
        this.$message.success(res.message)
      })
    }
  }

小结

登录的逻辑是什么?
把前端标签准备好, 数据绑定好, 在点击事件中走完表单验证逻辑, 调用接口传参给后台, 根据后台返回的code做前端页面结果提示

10.登录-结果存入vuex中

目标

把登录成功, 后台返回的token字符串存到vuex中

讲解

  1. src/store/index.js中定义, state里的token变量, 以及更新token的updateToken mutation 函数
export default new Vuex.Store({
  state: {
    // 1. 用来存储登录成功之后,得到的 token
    token: ''
  },
  mutations: {
    // 2. 更新 token 的 mutation 函数
    updateToken(state, newToken) {
      state.token = newToken
    }
  }
})
  1. src/views/login/index.vue中, 在成功后, 调用vuex里的mutations方法

可以直接调用 / 映射调用

import { mapMutations } from 'vuex'
export default {
 // ...其他
 methods: {
   ...mapMutations(['updateToken']),
   // 登录按钮->点击事件
   async loginFn () {
     this.$refs.loginRef.validate(async valid => {
       if (!valid) return
       // 1. 发起登录的请求
       const { data: res } = await loginAPI(this.loginForm)
       // 2. 登录失败
       if (res.code !== 0) return this.$message.error(res.message)
       // 3. 登录成功
       this.$message.success(res.message)
       // 4. 保存到vuex中
       this.updateToken(res.token)
     })
   }
 }
}

小结

登录后获取token, 保存vuex的代码执行思路是?
在登录接口返回响应成功后, 提取后台返回的token字符串, 调用mutations方法, 把值暂存到vuex的state内变量上, 但是仅仅在内存中, 刷新后state里token变量会变成空字符串(又相当于没登录一样)

11.登录-持久化存储vuex

目标

刷新vuex的值会回归初始化, 如果在保存到vuex时, 它能自动保存到浏览器本地, 默认从浏览器本地取呢?

讲解

自己写localStorage.setItem等 需要一个个写, 很麻烦

这里介绍一个vuex的插件包叫做vuex-persistedstate@3.2.1版本(配合vue2使用, 默认最新版是配合vue3使用)

  1. 下载此包到当前工程中
yarn add vuex-persistedstate@3.2.1
  1. src/store/index.js中, 导入并配置
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    // 1. 用来存储登录成功之后,得到的 token
    token: ''
  },
  mutations: {
    // 2. 更新 token 的 mutation 函数
    updateToken (state, newToken) {
      state.token = newToken
    }
  },
  // 配置为 vuex 的插件
  plugins: [createPersistedState()]
})
  1. 这次再来重新登录, 查看浏览器调试工具vuex和浏览器本地存储位置, 是否自动同步进入
  2. 刷新网页看调试工具里vuex的默认值确实从本地取出了默认值, 保证了vuex的持久化

小结

vuex为何要做持久化?
vuex运行时的值保存在内存里, 如果刷新vuex的变量会变成初始化的,所以让他的默认初始化的值从本地取, 当有人赋值给vuex也同步覆盖式保存到本地一份

12.登录-跳转布局页

目标

完成主页的标签和样式以及路由, 然后登录成功跳转

讲解

  1. 新建页面组件src/views/layout/index.vue, layout布局页面(它右下角包含的是主页), 直接根据需求画面, 直接复制标签和样式
<template>
  <el-container class="main-container">
    <!-- 头部区域 -->
    <el-header>
      <!-- 左侧的 logo -->
      <img src="../../assets/images/logo.png" alt="" />
      <!-- 右侧的菜单 -->
      <el-menu
        class="el-menu-top"
        mode="horizontal"
        background-color="#23262E"
        text-color="#fff"
        active-text-color="#409EFF"
      >
        <el-submenu index="1">
          <template slot="title">
            <!-- 头像 -->
            <img src="../../assets/images/logo.png" alt="" class="avatar" />
            <span>个人中心</span>
          </template>
          <el-menu-item index="1-1"><i class="el-icon-s-operation"></i>基本资料</el-menu-item>
          <el-menu-item index="1-2"><i class="el-icon-camera"></i>更换头像</el-menu-item>
          <el-menu-item index="1-3"><i class="el-icon-key"></i>重置密码</el-menu-item>
        </el-submenu>
        <el-menu-item index="2"><i class="el-icon-switch-button"></i>退出</el-menu-item>
      </el-menu>
    </el-header>
    <el-container>
      <!-- 侧边栏区域 -->
      <el-aside width="200px">Aside</el-aside>
      <el-container>
        <!-- 页面主体区域 -->
        <el-main>
          Main.vue后台主页
        </el-main>
        <!-- 底部 footer 区域 -->
        <el-footer>© www.itheima.com - 黑马程序员</el-footer>
      </el-container>
    </el-container>
  </el-container>
</template>

<script>
export default {
  name: 'my-layout'
}
</script>

<style lang="less" scoped>
.main-container {
  height: 100%;
  .el-header,
  .el-aside {
    background-color: #23262e;
  }
  .el-header {
    padding: 0;
    display: flex;
    justify-content: space-between;
  }
  .el-main {
    overflow-y: scroll;
    height: 0;
    background-color: #F2F2F2;
  }
  .el-footer {
    background-color: #eee;
    font-size: 12px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}

.avatar {
  border-radius: 50%;
  width: 35px;
  height: 35px;
  background-color: #fff;
  margin-right: 10px;
  object-fit: cover;
}
</style>
  1. src/router/index.js路由中配置规则和组件
{
    path: '/',
    component: () => import('@/views/layout')
}
  1. src/views/login/index.vue登录页面, 登录成功后跳转到主页
// 登录成功之后,跳转到后台主页
this.$router.push('/')

小结

layout布局页面是什么作用?
如果发现主页有固定的部分, 比如固定左侧导航/固定头部导航/固定底部导航, 那么这个标签放在layout, 在这个layout页面切换的部分就是嵌套的下级路由

13.退出登录

目标

完成退出登录的功能, 和业务学习

讲解

核心思想: 退出登录就是清除vuex和本地所有缓存的值, 然后页面强制切换到登录页面

  1. 退出登录按钮, 点击事件绑定
<el-menu-item index="2" @click="logoutFn"><i class="el-icon-switch-button"></i>退出</el-menu-item>
  1. 实现对应事件处理函数和提示
methods: {
    logoutFn () {
      // 询问用户是否退出登录
      this.$confirm('您确认退出登录吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          // TODO:执行退出登录的操作
        })
        .catch((err) => err)
    }
  }
  1. 执行退出逻辑代码
.then(() => {
    // TODO:执行退出登录的操作
    // 1. 清空 token
    this.$store.commit('updateToken', '')
    // 2. 跳转到登录页面
    this.$router.push('/login')
})

小结

  1. 退出登录的业务逻辑是什么?
    就是把vuex和本地的值清空, 然后页面强制跳转到登录页面

  2. 为何退出登录不用调用后台接口?
    因为我们采用的是前端存储token来表名用户登录的身份, 没有做单点登录(就是多个设备只能保证1个设备登录状态), 所以后端无需记录登录状态所以无接口调用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容