相关资料

  1. vue-cli脚手架: https://cli.vuejs.org/zh/
  2. vue官网: https://cn.vuejs.org/v2/guide/index.html

(一) 创建和配置项目

(1) 安装vue-cli脚手架

  1. npm install -g @vue/cli

(2) 查看vue脚手架版本

  1. vue --version

(3) 创建一个新项目

官网文档地址

  1. vue create hello-world // 1.创建项目
  1. cd hello-world // 2.进入项目文件夹
  2. npm run serve // 3.运行项目

若出现一下问题: 安装10.0版本的nodejs可以解决问题
nodejs下载地址: https://npm.taobao.org/mirrors/node
image.png

(4) hello-world项目目录结构

  1. 单页应用single-page application,简称 SPA, hello-world项目中在public文件夹有一个index.html也是项目中唯一一个html文件
  2. src文件夹: 源码文件夹, 我们将在这个文件去编写代码
  3. .gitignore: 记录哪些文件不提交
  4. babel.config.js: babel是用来将es6转成js5的工具, 这个文件是这个工具的配置

    (5) vue组件

  5. 父组件 ```javascript

  1. 2. 子组件
  2. ```javascript
  3. <template>
  4. <div class="footer">
  5. <span>{{tab}}</span>
  6. <span>影院</span>
  7. <span>我的</span>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. data() {
  13. return {
  14. tab: '首页'
  15. }
  16. },
  17. created() {
  18. console.log('footer组件')
  19. }
  20. }
  21. </script>
  22. <style>
  23. .footer{
  24. position: fixed;
  25. bottom: 0;
  26. height: 50px;
  27. width: 100%;
  28. display: flex;
  29. justify-content: space-around;
  30. }
  31. </style>

(6) 禁用eslint

  1. // 根目录新增vue.config.js
  2. module.exports = {
  3. lintOnSave: false
  4. }

(7) devtool

vue开发调试工具

  1. 下载 http://soft.huruqing.cn
  2. 添加到chrome扩展程序里

    (8) 查看webpack配置

    vue inspect > output.js

    (二) 添加less支持

  3. npm install less less-loader@6.0.0 —save-dev

  4. 在vue文件这样写即可, scoped表示样式只在当前文件有效, 不会影响其他组件

    1. <style lang="less" scoped>
    2. #app {
    3. a {margin-left: 15px;}
    4. }
    5. </style>

    image.png
    出现这个问题是因为less-loader版本太高, 执行这两步操作即可

  5. npm uninstall less-loader

  6. npm install less-loader@6.0.0

    (三) vue路由配置

    (1)一个简单路由配置

  7. npm i vue-router

  8. 在src内创建router文件夹, 新建index.js(代码如下)
  9. 在src创建views文件夹, 存放各个模块的组件, components文件夹存放的公共的组件
  10. 在main.js里, 把router挂载到vue的实例
  11. 配置路由出口, 详见下方第(2)点router-view
  12. 使用router-link进行跳转, 详见下方第(3)点路由跳转
  1. // router/index.js
  2. import Vue from "vue";
  3. import Router from "vue-router";
  4. Vue.use(Router);
  5. export default new Router({
  6. routes: [
  7. {
  8. path: "/",
  9. redirect: "/index"
  10. },
  11. {
  12. path: "/cart",
  13. component: () => import("@/views/cart/index")
  14. },
  15. {
  16. path: "*",
  17. component: () => import("@/views/components/NotFound")
  18. },
  19. ]
  20. })
  1. // main.js 代码
  2. import Vue from 'vue'
  3. import App from './App.vue'
  4. import router from './router/index'
  5. Vue.config.productionTip = false
  6. new Vue({
  7. // 把router挂载到vue实例
  8. router,
  9. render: h => h(App),
  10. }).$mount('#app')

(2) router-view

  1. 路由出口
  2. 路由匹配到的组件将渲染在这里
  3. 在app.vue配置

    1. <template>
    2. <div id="app">
    3. <img alt="Vue logo" src="./assets/logo.png" />
    4. <!-- 路由出口 -->
    5. <!-- 路由匹配到的组件将渲染在这里 -->
    6. <router-view></router-view>
    7. <!-- 在页面显示子组件 -->
    8. <Footer></Footer>
    9. </div>
    10. </template>
    11. <script>
    12. // 导入子组件
    13. import Footer from "@/components/Footer";
    14. export default {
    15. name: "App",
    16. // 注册组件
    17. components: {
    18. Footer
    19. }
    20. };
    21. </script>
    22. <style>
    23. #app {
    24. text-align: center;
    25. margin-top: 60px;
    26. }
    27. </style>

    (3) 路由跳转

    ```javascript // 方式一 cart

// 方式二 this.$router.push(‘/cart’);

  1. <a name="cI4Wm"></a>
  2. ### (4) 子路由配置
  3. 使用子路由进行模块路由配置,结构比较分明<br />比如我们的网站有商品模块,有列表页面和详情页面, 路由如下<br />/product 商品模块总路由<br />/prodcut/list 子路由<br />/product/detail 子路由
  4. ```javascript
  5. {
  6. path: '/product',
  7. component: () => import('@/views/product/index'),
  8. children: [
  9. {
  10. path: 'list',
  11. component: ()=>import('@/views/product/children/list')
  12. },
  13. {
  14. path: 'detail',
  15. component: ()=>import('@/views/product/children/detail')
  16. }
  17. ]
  18. }

(5) active-class

active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换;

  1. 只要路由中包含to里面的路由, 就能匹配到, 就会高亮, 比如: /product, /product/list, /product/detail都会使下面的第二个router-link高亮
  2. exact 表示精确匹配, 只有路由完全一样才能被匹配
    1. <router-link to="/" active-class="on" exact>首页</router-link>
    2. <router-link to="/product" active-class="on">product</router-link>
    3. <router-link to="/cart" active-class="on">cart</router-link>
    4. <router-link to="/my" active-class="on">my</router-link>
    5. <router-link to="/order" active-class="on">order</router-link>

(6) history模式

  1. vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
  2. 如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
  3. 以前使用history需要后端支持, 现在不需要了

    1. const router = new VueRouter({
    2. mode: 'history', // 默认hash
    3. routes: [...]
    4. })

    (7) 默认跳转(redirect重定向)

    当访问 ‘/‘, 我们使用redirect使它默认跳到 ‘/product’

    1. {
    2. path: '/',
    3. redirect: '/product'
    4. },

    (8) 404配置

    假如用户访问了一个没有的路由, 我们让它跳转到404页面

    1. {
    2. path: '*',
    3. component:()=>import('@/components/NotFound')
    4. }

    (四) vant有赞ui库

    文档地址: https://vant-contrib.gitee.io/vant/#/zh-CN/

  4. npm i vant -S 安装vant

  5. 导入所有组件(按需导入请看文档)

    1. // 在main.js添加以下内容
    2. import Vue from 'vue';
    3. import Vant from 'vant';
    4. import 'vant/lib/index.css';
    5. Vue.use(Vant);

    (五) 封装axios

    封装axios让我们请求数据更happy

  6. npm i axios -s

  7. 在src下新建utils文件夹
  8. 新建request.js文件 ```javascript import axios from ‘axios’; import { Dialog } from ‘vant’;

const get = (url, data) => { return new Promise((resolve, reject) => { axios.get(url,{params: data}).then(res=> { if(res.data.code == 666) { resolve(res.data); } else { Dialog({ message: res.data.msg }); } }).catch(err=>{ Dialog({ message:’网络请求失败, 请稍后再试’ }); }); }) }

const post = (url, data) => { return new Promise((resolve, reject) => { axios.post(url, data).then(res=> { if(res.data.code == 666) { resolve(res.data); } else { Dialog({ message: res.data.msg }); } }).catch(err=>{ Dialog({ message:’网络请求失败, 请稍后再试’ }); }); }) }

export default { get, post }

  1. <a name="V8FY9"></a>
  2. ## (六) 集中管理所有请求
  3. 1. 在src下新建api文件夹
  4. 1. 新建index.js
  5. ```javascript
  6. import axios from '@/utils/request'
  7. let baseUrl = 'http://huruqing.cn:3000/api';
  8. // 电影模块
  9. export const fetchFilmList =(data={}) => axios.get(baseUrl+'/film/getList', data);
  10. export const fetchFilmDetail = (data={}) => axios.get(baseUrl+'/film/getDetail', data);
  11. // 影院模块
  12. export const fetchCinemalList =(data={}) => axios.get(baseUrl+'/film/getList', data);
  13. // 其他模块

(七) vue路由跳转和传参

(1) 路由跳转的两种方式

  1. // 方式一
  2. <router-link to="xxxx"></router-link>
  3. // 方式二
  4. this.$router.push();

(2) 三种路由传参方式

传参

  1. 通过params传参
  2. 动态路由传参
  3. 通过query传参

获取参数

  1. this.$route.params
  2. this.$route.query

注意: router和route不是一回事

1.通过name+params传参

  1. // 1.配置路由的时候添加name
  2. {
  3. path: '/product',
  4. name: 'product'
  5. component: ()=>import('@/views/product/index')
  6. },
  7. // 2.跳转
  8. this.$router.push({ name: 'product', params: { productId: '123' }})
  9. // 3.接收参数
  10. this.$route.params.productId

2.动态路由传参

  1. // 1.路由配置
  2. {
  3. path: '/detail/:productId,
  4. name: 'detail',
  5. component: Detail
  6. }
  7. // 2.页面,参数接在路由后面
  8. <router-link to="/detail/19"></router-link>
  9. // 获取参数
  10. this.$route.params.productId(上面配置是id,这里就用id来接收参数)

3.通过path+query传参

  1. // 带查询参数,query传参会把参数拼接到地址栏,变成 /register?plan=aaa, 使用了path,参数不能通过params传递
  2. this.$router.push({ path: '/register', query: { plan: 'aaa' }})
  3. // 获取参数
  4. this.$route.query.plan;


(八) 导入重置样式和公共样式

  1. // main.js
  2. import Vue from 'vue'
  3. import App from './App.vue'
  4. import router from './router/index'
  5. import Vant from 'vant';
  6. import 'vant/lib/index.css';
  7. // 导入重置样式和公共样式
  8. import '@/assets/style/reset.less'
  9. import '@/assets/style/common.less'
  10. Vue.use(Vant);
  11. Vue.config.productionTip = false
  12. new Vue({
  13. router,
  14. render: h => h(App),
  15. }).$mount('#app')

(九) 模拟数据

  1. 文档地址: https://www.npmjs.com/package/json-server
  2. npm i json-server -g //全局安装
  3. 创建db.json
  4. 启动json-server

    1. json-server --watch db.json
    1. // db.json
    2. {
    3. "posts": [
    4. { "id": 1, "title": "json-server", "author": "typicode" }
    5. ],
    6. "comments": [
    7. { "id": 1, "body": "some comment", "postId": 1 }
    8. ],
    9. "profile": { "name": "typicode" }
    10. }
  5. 访问接口

    1. http://localhost:3000/posts/1
  6. 将命令添加到package.json, 可以使用 npm run json 启动项目

    1. "scripts": {
    2. "json": "json-server --watch db.json"
    3. },

    (十) 父子组件通信

    1.父传子

  • 父组件给子组件绑定属性, 属性的值是需要传递的信息
  • 子组件通过props接收父组件的信息 ```javascript // 父组件

// 子组件

Expected Number with value NaN, got String …. 预期得到的数字, 但是得到是字符串

  1. <a name="wV3Gp"></a>
  2. #### 2. 子传父
  3. 1. 父组件在子组件上绑定一个自定义事件(事件名称我们自己定义的, vue本身是没有这个事件的)
  4. 1. 父组件给自定义事件绑定一个函数, 这个函数可以接受来自子组件的数据
  5. 1. 子组件使用$emit触发(调用)该事件, 并把数据以参数形式传给父组件
  6. ```javascript
  7. // 父组件
  8. <template>
  9. <div class="father">
  10. <h3>父组件</h3>
  11. <hr>
  12. <!-- @getMsg是自定义事件,它绑定了一个叫getMsg的函数,当事件被触发,函数就会被调用 -->
  13. <child @getMsg="getMsg"></child>
  14. </div>
  15. </template>
  16. <script>
  17. import Child from './Child.vue';
  18. export default {
  19. components: {
  20. Child
  21. },
  22. methods: {
  23. // data是子组件传回来的信息
  24. getMsg(data) {
  25. console.log(data);
  26. }
  27. }
  28. };
  29. </script>
  30. // 子组件
  31. <template>
  32. <div class="Falterh">
  33. <h4>子组件</h4>
  34. <button @click="send">发信息</button>
  35. </div>
  36. </template>
  37. <script>
  38. export default {
  39. methods: {
  40. // 给父组件发送信息
  41. send() {
  42. /**
  43. * 使用$emit触发父组件的自定义事件
  44. * @param getMsg-父组件自定义事件,
  45. * @param data-传递给父组件的数据
  46. */
  47. let data = {
  48. msg1: '父亲大人安好',
  49. msg2: '老爸,我没有生活费了'
  50. }
  51. this.$emit('getMsg',data);
  52. }
  53. }
  54. };
  55. </script>
  56. // 综合例子练习: 定义父组件和子组件, 实现需求: 父=>子:儿子,好好努力; 子=>父:父亲,保重身体
  57. // 父组件
  58. <template>
  59. <div>
  60. <h3>父组件</h3>
  61. <p>来自儿子的信息: {{info}}</p>
  62. <hr>
  63. <Son msg="儿子,好好努力" @getMsg="test"></Son>
  64. </div>
  65. </template>
  66. <script>
  67. import Son from './Son'
  68. export default {
  69. data() {
  70. return {
  71. info: ''
  72. }
  73. },
  74. // 注册组件
  75. components: {
  76. Son,
  77. },
  78. methods: {
  79. test(data) {
  80. this.info = data;
  81. }
  82. }
  83. };
  84. </script>
  85. // 子组件
  86. <template>
  87. <div>
  88. <h4>子组件</h4>
  89. <p>来自父亲的信息: {{msg}}</p>
  90. <br>
  91. <button @click="send">给父亲发消息</button>
  92. </div>
  93. </template>
  94. <script>
  95. export default {
  96. props: ['msg'],
  97. methods: {
  98. send() {
  99. // 触发父组件绑定在子组件上的自定义事件
  100. let str = '父亲,保重身体';
  101. this.$emit('getMsg',str);
  102. }
  103. }
  104. };
  105. </script>

// 有赞的导航栏

  1. // 父组件
  2. <Nav-Bar
  3. title="标题"
  4. left-text="返回"
  5. right-text="按钮"
  6. @click-left="onClickLeft"
  7. @click-right="onClickRight"
  8. />
  9. // 子组件
  10. <template>
  11. <div class="nav-bar">
  12. <span class="blue" @click="click1">{{ leftText }}</span>
  13. <span>{{ title }}</span>
  14. <span class="blue" @click="click2">{{ rightText }}</span>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. props: ["left-text", "title", "right-text"],
  20. methods: {
  21. // 点击左边
  22. click1() {
  23. this.$emit("click-left");
  24. },
  25. // 点击右边
  26. click2() {
  27. this.$emit("click-right");
  28. },
  29. },
  30. };
  31. </script>
  32. <style>
  33. body{background: #ebebeb;margin: 0;}
  34. .blue{color: #1989fa;}
  35. .nav-bar {
  36. background: #fff;
  37. padding:0 10px;
  38. display: flex;
  39. justify-content: space-between;
  40. align-items: center;
  41. height: 50px;
  42. }
  43. </style>


(十一) slot插槽

元素作为承载分发内容的出口
一个内存插槽, 当内存插上之后,插槽就可以接收来自内存的信息, slot取名插槽含义也贴切, 在子组件配置插槽slot, 当父组件”插”信息进来的时候, 插槽slot就能接收到这个信息. slot插槽大大的扩展子组件的功能。
第3节 移动端项目实战 - 图4
image.png

1. vant有赞ui库中slot的例子

  1. <van-nav-bar title="标题" left-text="返回" left-arrow>
  2. <p slot="right">
  3. <van-icon name="search" size="18" />
  4. </p>
  5. </van-nav-bar>

2. 普通插槽

  1. // 子组件Child.vue代码
  2. <template>
  3. <div style="margin-top: 30px;background: gray;height: 200px;">
  4. <h5>这是子组件</h5>
  5. <slot></slot>
  6. </div>
  7. </template>
  8. // 父组件father.vue代码
  9. <template>
  10. <div>
  11. <h3>这是父组件</h3>
  12. <Child>
  13. <button>提交</button>
  14. </Child>
  15. </div>
  16. </template>
  17. <script>
  18. import Child from '@/components/Child'
  19. export default {
  20. components: {
  21. Child
  22. }
  23. };
  24. </script>

3. 具名插槽

  1. // father.vue代码
  2. <template>
  3. <div>
  4. <h3>这是父组件</h3>
  5. <Child>
  6. <header slot="header" style="background: yellow">这是头部</header>
  7. <footer slot="footer" style="background: green;">这是底部</footer>
  8. <div style="border:1px solid;">
  9. <button>a</button>
  10. <button>b</button>
  11. <button>c</button>
  12. <button>d</button>
  13. </div>
  14. </Child>
  15. </div>
  16. </template>
  17. <script>
  18. import Child from "@/components/Child";
  19. export default {
  20. components: {
  21. Child
  22. }
  23. };
  24. </script>
  25. 接收父组件带 slot="footer" 的内容
  26. 接收不带slot="xxx" 的内容
  27. // Child.vue代码
  28. <template>
  29. <div style="margin-top: 30px;background: gray;height: 200px;">
  30. <h5>这是子组件</h5>
  31. <!--接收父组件带 slot="header" 的内容-->
  32. <slot name="header"></slot>
  33. <!--接收父组件带 slot="footer" 的内容-->
  34. <slot name="footer"></slot>
  35. <!--接收剩余内容-->
  36. <slot></slot>
  37. </div>
  38. </template>

(十二) 混入mixin

mixin 其实是一个对象,里面的结构大致跟普通组件的 script 里面的一样,有 data 属性,钩子函数和方法等 混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

1.组件内混入

  1. // mixin.js
  2. export default {
  3. data: function() {
  4. return {
  5. username: "huruqing",
  6. age: 100
  7. };
  8. },
  9. created() {
  10. console.log('这是混入对象')
  11. },
  12. methods: {
  13. say() {
  14. console.log('hahahhahahha');
  15. }
  16. }
  17. };
  18. // demo.vue
  19. <template>
  20. <div>
  21. <p>{{username}}</p>
  22. <p>{{msg}}</p>
  23. <p>{{age}}</p>
  24. </div>
  25. </template>
  26. <script>
  27. import mixin from './mixin'
  28. export default {
  29. mixins:[mixin],
  30. data() {
  31. return {
  32. username: '张三',
  33. msg: 'hahahahahahha'
  34. }
  35. },
  36. created() {
  37. console.log('组件的created');
  38. this.say();
  39. }
  40. }
  41. </script>

2.全局混入

  1. // mixin.js
  2. export default {
  3. methods: {
  4. showLoading() {
  5. this.$toast.loading({
  6. message: '加载中...',
  7. forbidClick: true,
  8. duration:0
  9. });
  10. },
  11. closeLoading() {
  12. this.$toast.clear();
  13. }
  14. }
  15. }
  16. // main.js,这个代码放在Vue.use(Vant)之后
  17. import mixin from './mixin/index';
  18. Vue.mixin(mixin);
  19. // 其他组件就可以直接使用下面代码来显示loading
  20. this.showLoading();

(十三) 跨组件通信vuex

相关资料

vuex 官网文档地址: https://vuex.vuejs.org/zh/
修改年龄接口: /changeAge.json?newAge=xxx

(1) vuex 是什么

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。学习vuex掌握以下几点就差不多了.

  1. 普通对象: 创建对象, 定义对象属性, 读取属性, 修改属性
  2. vuex: 创建仓库, 定义状态, 读取状态, 修改状态(核心关键点)
  3. 响应式
  4. vuex的5个核心概念
    1. state 状态
    2. getters 获取
    3. mutations 修改状态
    4. actions 修改状态
    5. modules 模块

(2) 在项目中使用配置 vuex

  1. 创建仓库 ```javascript
  2. 安装vuex: npm i vuex -S
  3. /sotre/index.js 代码如下:

import Vuex from ‘vuex’; import Vue from ‘vue’; Vue.use(Vuex);

export default new Vuex.Store({ });

  1. 2. 挂载到根节点
  2. ```javascript
  3. import Vue from 'vue'
  4. import App from './App.vue'
  5. import router from './router/index'
  6. import store from './store/index'
  7. Vue.config.productionTip = false
  8. new Vue({
  9. router,
  10. store,
  11. render: h => h(App),
  12. }).$mount('#app')

(3) 在项目中使用 vuex 进行跨组件通信

  1. 定义状态 ```javascript import Vuex from ‘vuex’; import Vue from ‘vue’; Vue.use(Vuex);

export default new Vuex.Store({ // 定义状态 state: { name: ‘王美丽’, age: 20 } });

  1. 2. **读取状态**
  2. - 使用mapState辅助函数来读取
  3. ```javascript
  4. //写法1
  5. computed: mapState(['name','age','date'])
  6. // 写法2
  7. computed: {
  8. ...mapState(['name','age','date'])
  9. }
  • 直接读取
    1. // this.$store.state.xxx;
    2. <template>
    3. <div class="page">
    4. <p>新娘姓名: {{$store.state.name}}</p>
    5. <p>新娘年龄: {{$store.state.age}}</p>
    6. </div>
    7. </template>
  1. 修改状态 mutation
    1. 定义mutation ```javascript // 定义mutation import Vuex from ‘vuex’; import Vue from ‘vue’; Vue.use(Vuex);

export default new Vuex.Store({ // 定义状态 state: { name: ‘王美丽’, age: 20, date: ‘2021-10-01’ }, // 定义mutation,用来修改状态 mutations: { /**

  1. * 定义一个用来修改日期的mutation
  2. * @param {*} state 状态
  3. * @param {*} payload 传入来的数据
  4. */
  5. updateDate(state,newDate) {
  6. state.date = newDate;
  7. }
  8. }

});

  1. 1. 提交mutation
  2. ```javascript
  3. // this.$store.commit('updateDate', this.newDate);
  4. <template>
  5. <div class="page">
  6. <header>张三组件</header>
  7. <p>
  8. <input type="text" v-model="newDate">
  9. <button @click="changeDate">修改结婚日期</button>
  10. </p>
  11. </div>
  12. </template>
  13. <script>
  14. export default {
  15. data() {
  16. return {
  17. newDate: ''
  18. }
  19. },
  20. methods: {
  21. changeDate() {
  22. // 提交mutation
  23. this.$store.commit('updateDate',this.newDate);
  24. }
  25. }
  26. }
  27. </script>

注意:

  • 修改状态必须通过mutation
  • mutation必须是同步函数

(4) 异步改状态 action

  1. 定义mutation
  2. 定义action, 在action提交mutation
  3. 派发action

    1. this.$store.dispatch('updateAgeAction', this.newAge);

    使用action修改状态流程:
    用户修改数据 => 派发action => action提交mutation => 修改状态 => 用户界面更新
    image.png

    (5) 派生(扩展)状态 getters

  4. 定义getter (getter有的像计算属性computed)

    1. // store/index.js
    2. getters: {
    3. // 根据身份证扩展出一个新的状态:生日
    4. birthday(state) {
    5. return state.cardId.replace(/\d{6}(\d{4})(\d{2})(\d{2}).*/,'$1年$2月$3日');
    6. }
    7. },
  5. 获取getter的值(用法跟state类似)

    • 直接获取 this.$store.getters.xxx
    • 通过mapState进行获取 ```javascript // 直接获取

// 使用mapGetter是获取

  1. ps: getter非必须, 我们完全可以通过computed来定义一个新的属性(依赖仓库的state), 但如果很多个组件都要用到这个属性, 放在computed里来定义就显得冗余了, 最好定义一个getter来扩展新的状态(属性)
  2. <a name="594b0307"></a>
  3. ### (6) 模块化 modules
  4. 1. 导出模块, 模块的代码如下:
  5. ```javascript
  6. // cart模块 /store/modules/cart.js
  7. export default {
  8. state: {
  9. cartNum: 0
  10. },
  11. getters: {},
  12. mutations: {},
  13. actions: {}
  14. }
  1. 在仓库中加入modules

    1. // /store/index.js
    2. import cart from './modules/cart'
    3. export default new Vuex.Store({
    4. state: {},
    5. getters: {},
    6. mutations: {},
    7. actions: {},
    8. modules: {
    9. cart
    10. }
    11. })
  2. 获取模块中的状态

    1. this.$store.state.cart.cartNum;

    (7) vuex持久化

  3. npm install vuex-persistedstate —save

  4. 在 /store/index.js中导入并挂载 ```javascript import createPersistedState from “vuex-persistedstate”

conststore =new Vuex.Store({ plugins: [createPersistedState()] }

  1. <a name="MaRQ5"></a>
  2. #### (8) html5本地存储
  3. 1. localStorage
  4. ```javascript
  5. (1) 存数据 localStorage.setItem('name','王美丽');
  6. (2) 取数据 localStorage.getItem('name');
  7. (3) 清除数据 localStorage.clear();
  1. sessionStorage
    1. (1) 存数据 sessionStorage.setItem('name','王美丽');
    2. (2) 取数据 sessionStorage.getItem('name');
    3. (3) 清除数据 sessionStorage.clear();
  2. localStorage和sessionStorage的区别

    1. localStorage永久存储, 如果不清理一直存在
    2. sessionStorage临时存储, 浏览器关闭就销毁

      (十四) 过滤器filter

      (十五) token和session

      (1) session

  3. 为什么要有 session 的出现?

答:是由于网络中 http 协议造成的,因为 http 本身是无状态协议,这样,无法确定你的本次请求和上次请求是不是你发送的。如果要进行类似论坛登陆相关的操作,就实现不了了。

  1. session 生成方式?

答:浏览器第一次访问服务器,服务器会创建一个 session,然后同时为该 session 生成一个唯一的会话的 key,也就是 sessionid,然后,将 sessionid 及对应的 session 分别作为 key 和 value 保存到缓存中,也可以持久化到数据库中,然后服务器再把 sessionid,以 cookie 的形式发送给客户端。这样浏览器下次再访问时,会直接带着 cookie 中的 sessionid。然后服务器根据 sessionid 找到对应的 session 进行匹配; 还有一种是浏览器禁用了 cookie 或不支持 cookie,这种可以通过 URL 重写的方式发到服务器;

  1. 简单来讲,用户访问的时候说他自己是张三,他骗你怎么办? 那就在服务器端保存张三的信息,给他一个 id,让他下次用 id 访问。

    (2) token

  2. 为什么会有 token 的出现?

  3. 答:首先,session 的存储是需要空间的,其次,session 的传递一般都是通过 cookie 来传递的,或者 url 重写的方式;而 token 在服务器是可以不需要存储用户的信息的,而 token 的传递方式也不限于 cookie 传递,当然,token 也是可以保存起来的;
  4. token 的生成方式?
  5. 答:浏览器第一次访问服务器,根据传过来的唯一标识 userId,服务端会通过一些算法,如常用的 HMAC-SHA256 算法,然后加一个密钥,生成一个 token,然后通过 BASE64 编码一下之后将这个 token 发送给客户端;客户端将 token 保存起来,下次请求时,带着 token,服务器收到请求后,然后会用相同的算法和密钥去验证 token,如果通过,执行业务操作,不通过,返回不通过信息;

    (3) token 和 session 的区别?

  6. token 和 session 其实都是为了身份验证,session 一般翻译为会话,而 token 更多的时候是翻译为令牌; session 服务器会保存一份,可能保存到缓存,文件,数据库;同样,session 和 token 都是有过期时间一说,都需要去管理过期时间; 其实 token 与 session 的问题是一种时间与空间的博弈问题,session 是空间换时间,而 token 是时间换空间。两者的选择要看具体情况而定。

  7. 方案 A :我发给你一张身份证,但只是一张写着身份证号码的纸片。你每次来办事,我去后台查一下你的 id 是不是有效。
  8. 方案 B :我发给你一张加密的身份证,以后你只要出示这张卡片,我就知道你一定是自己人。 就这么个差别。

    (4) axios请求每次都带上token

    1. axios.get(url,{headers:{'user-token':token}, params: data})