尚品汇学习笔记

地址

快捷键

c o n t r o l + f − − − − G o o g l e 搜索 control+f ----Google搜索 control+fGoogle搜索

c o n t r o l + r − − − − 替换所有指定字符 control+r ----替换所有指定字符 control+r替换所有指定字符

a l t + 左键 − − − − 对多行进行处理 alt + 左键----对多行进行处理 alt+左键对多行进行处理

c o n t r o l + a l t + a − − − − Q Q 截屏快键键 control+alt+a----QQ截屏快键键 control+alt+aQQ截屏快键键

模块开发步骤

1)先静态页面+静态组件拆分

2)发请求(API)

3)vuex(三连环)

  • 在api中抛出函数,index.js中
//API统一管理
import request from "./request";
//http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList
export const reqCategoryList = () => {return request({url: '/product/getBaseCategoryList',method: 'get' })};
  • 在组件中使用
this.$store.dispatch('函数名');
  • 在store下引入函数
import { reqCategoryList } from "@/api";

注意:这里的“params={}”指params默认参数是空对象{}

const actions = {
    async getSearchList({commit},params={}){
        let result=await reqGetSearchInfo(params);
        if(result.code===200){
            commit('GETSEARCHLIST',result.data)
        }else{
            console.log('请求失败')
        }
    }
}

4)组件获取仓库数据,动态展示数据

路由

注册路由

1.引入:

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

2.抛出:

Vue.use(VueRouter)
export default new VueRouter({
 routes:[]})

路由滚动行为

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滚动到哪个的位置
       return { x: 0, y: 0 }
  }
})

3.重定向

{
   path:'/',
   redirect: '/home'  
}

在APP中要加上

4.在main.js中引入注册

import Vue from 'vue'
import App from './App.vue'
import router from '@/router'
new Vue({
  render: h => h(App),
  router
}).$mount('#app')

2.route传参

1.编程式导航
this.$router.push({
                name: 'sousuo',
                params: {
                    keyword: this.keyword   
                },
                query: {
                    keyword: this.keyword
                }
            })

使用下面代码解决点击多下会报错问题,修改VueRouter原型中的push,replace函数

let orginPush = VueRouter.prototype.push
let orginReplace = VueRouter.prototype.replace
VueRouter.prototype.push = function(location, onResolve, onReject) {
    if (onResolve || onReject) return orginPush.call(this, location, onResolve, onReject)
    return orginPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function(location, onResolve, onReject) {
    if (onResolve || onReject) return orginReplace.call(this, location, onResolve, onReject)
    return orginReplace.call(this, location).catch(err => err)
}

在router下面的index.js中写上params的参数

props接受参数,一般不定义,在组件中接受

{   
            name:'sousuo',
            path:'/search/:keyword?',
            component:Search,
            meta:{show:true},
            props:($route)=>({keyword:$route.params.keyword,keyword2:$route.query.keyword})
        },

注意:path和params不能联合使用,params不能传空字符串,可以加上||unidentified

2.声明式导航

3.query传参

要在ruter下的index.js中配置props,不然接受不到

this.$route.query.参数名

3.meta使用

配置在route下的index.js中

{
            path:'/login',
            component:Login,
            meta:{show:false}
        },

使用情形:与v-show并用,决定组件是否渲染

<template>
  <div>
    <Header/>
    <router-view></router-view>
    <Footer v-show="$route.meta.show"></Footer>
  </div>
</template>

4.路由守卫

  1. 作用:对路由进行权限控制

  2. 分类:全局守卫、独享守卫、组件内守卫

  3. 全局守卫:

    //全局前置守卫:初始化时执行、每次路由切换前执行
    router.beforeEach((to,from,next)=>{
    	console.log('beforeEach',to,from)
    	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
    		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
    			next() //放行
    		}else{
    			alert('暂无权限查看')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next() //放行
    	}
    })
    
    //全局后置守卫:初始化时执行、每次路由切换后执行
    router.afterEach((to,from)=>{
    	console.log('afterEach',to,from)
    	if(to.meta.title){ 
    		document.title = to.meta.title //修改网页的title
    	}else{
    		document.title = 'vue_test'
    	}
    })
    
  4. 独享守卫:

    beforeEnter(to,from,next){
    	console.log('beforeEnter',to,from)
    	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
    		if(localStorage.getItem('school') === 'atguigu'){
    			next()
    		}else{
    			alert('暂无权限查看')
    			// next({name:'guanyu'})
    		}
    	}else{
    		next()
    	}
    }
    
  5. 组件内守卫:

    //进入守卫:通过路由规则,进入该组件时被调用
    beforeRouteEnter (to, from, next) {
    },
    //离开守卫:通过路由规则,离开该组件时被调用
    beforeRouteLeave (to, from, next) {
    }
    

5.路由跳转注意事项

生命周期:

路由跳转时,旧组件会销毁

若是自己跳自己则不会触发生命周期函数。

注册全局组件

三级联动

指的是多个组件使用这个全局组件。

1.注册全局组件

在main.js中引入

import TypeNav from '@/components/TypeNav'
Vue.component('TypeNav', TypeNav)

注意:其中第一个参数是全局组件的名字,第二个参数是哪一个组件。TypeNav是一个文件夹,下面index.js文件里面有个TypeNav.vue,name:“TypeNav”。

2.使用全局组价

不需要使用components{}来注册,直接使用就可。

接口

api管理接口

主流用axios,安装 npm install --save axios

配置代理

在vue.config.js中配置

  //代理跨域  
devServer: {
    proxy: {
      '/api': {
        target: 'http://gmall-h5-api.atguigu.cn',
        changeOrigin: true,
        // pathRewrite: {
        //   '^/api': ''
        // }
      }
    }
  }
}

request.js

import axios from 'axios'
const request = axios.create({
    baseURL: "/api",
    timeout: 5000,
})
// 请求拦截器
request.interceptors.request.use(config => {
    return config});
//响应拦截器
request.interceptors.response.use(response => {
    return response.data},(error) => {
    return Promise.reject(new Error(error.message));
    })
export default request

index.js

抛出函数

//API统一管理
import request from "./request";
//http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList
export const reqCategoryList = () => {return request({url: '/product/getBaseCategoryList',method: 'get' })};

在main.js中注册

import {reqCategoryList} from '@/api/index' 
reqCategoryList();

进度条

在request.js中引入

其中进度条样式可以修改,在nprogress/nprogress.css中修改

//引入进度条
import nprogress from 'nprogress'
//引入进度条样式
import 'nprogress/nprogress.css'
request.interceptors.request.use(config => {
    //显示进度条
    nprogress.start();
    return config});
request.interceptors.response.use(response => {
    //隐藏进度条
    nprogress.done();
    return response.data},(error) => {
    return Promise.reject(new Error(error.message));
    })

vuex

vuex是个插件,状态管理库,集中式管理项目中组件公用的数据

vuex仓库储存数据不是持久化储存

使用情形:项目很大,组件很多,数据很多,数据维护很费劲,使用vuex

vuex

安装

npm install --save vuex@3

注册

在scr目录下新建store文件夹,在index.js中写入代码

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

//state:仓库中的数据
const state = {}
//mutations:修改仓库中的数据
const mutations = {
    //add(state,参数){
    //    state.数据 = 参数
    //    }
}
//actions:异步修改仓库中的数据
const actions = {
    //这里可以书写业务逻辑但不能修改state中的数据
    //ADD(commit,参数){
    //    commit('ADD',参数)
    }

//getters:计算属性
const getters = {}
//对外暴露一个store对象
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})

在main.js中注册

import store from '@/store/index'
new Vue({
  render: h => h(App),
  router,
  //注册store
  store
}).$mount('#app')

在组件中使用时:

this.$store.dispatch('函数名');

在store的index.js中注册多个vuex

//引入子vuex
import home from './home'
//暴露
export default new Vuex.Store({
    modules:{
        home,
    }
})

在子组件中写时,注意不用创建vuex模块

import { reqCategoryList } from "@/api";
const state={
    categoryList:[]
};
const mutations = {
    CATEGORYLIST(state,data){
        state.categoryList=data
    }
};
const actions = {

    async categoryList({commit}){
        let result=await reqCategoryList()
        if  (result.code===200){
            commit('CATEGORYLIST',result.data)
        }
    }
};
const getters = {};
export default{
    state,
    mutations,
    actions,
    getters
}

使用store中方法:

1.获取数据

首先在全局组件TypeNva中mounted(){}挂载中提交actions,获取接口中的列表等数据

    mounted(){
        this.$store.dispatch('categoryList')
    },

2.mapstate获取store中state中的数据:

两种方式
1.mapState中传入数组
import {mapState} from 'vuex';
computed: {
    ...mapState(['name', 'age']),//与state中的名字相同,在template中可以直接使用name,age
  },
2.mapState中传入对象

注意:当时用modules时,数组方法不可用,用对象方法:

import {mapState} from 'vuex';
computed: {
    ...mapState({
      name1: state => state.name+'123',//与state中的名字不相同,可以进行处理
      age: state => state.age
    })
   },
  },

eg:在store中使用modules

import {mapState} from 'vuex';
computed:{
 ...mapState({
 categoryList: state => state.home.categoryList   //state是参数,return state.home.categoryList给categoryList
     })
},

3.getters获取store中的数据

简化仓库中的数据,可以把将来组件中需要的数据简化一下,获取更方便

const getters = {
    goodsList(state){
        return state.searchList.goodsList || []
    },
    trademarkList(state){
        return state.searchList.trademarkList || []
    },
    attrsList(state){
        return state.searchList.attrsList || []
    }
}

注意:getters可以理解为计算属性,传入的参数是state对象

获取数据时用数组形式即可,不分模块

在想获取数据的组件中

import { mapGetters} from 'vuex'
    computed: {
      ...mapGetters(['goodsList']),
    },

函数防抖与节流

定义:防止用户操作过快使页面卡顿,加入lodash函数以后,使在一定时间内用户的操作只进行最后一次的操作。

只引入lodash中的throttle函数

import throttle from 'lodash/throttle';
methods:{
        //对changeIndex进行节流
        changeIndex: throttle(function(index){
            this.currentIndex = index
        }, 50),
        }

js文件的引入:

如果是默认暴露: import 包名 from ‘路径’

如果是 ? :import {。。。}from ‘路径’

自定义属性

概念

img的标准属性为src、alt等,但若写一个 data-info 则data-info叫自定义属性

作用

一般用来存储额外数据辅助完成某个功能

规范

自定义属性一律以 data- 开头,后面接名字,且名字中若多个单词用-隔开

例:data-info 、data-label、data-login-name等

为什么要加 data- 开头

方便区分什么是【标准属性】,什么是【自定义属性】
JavaScript操作自定义属性:dataset

语法

元素.dataset.自定义属性名

注意事项

不用加data-,后面遵守驼峰命名法
例:某元素的自定义属性叫 data-label,则 元素.dataset.label
通过dataset可以获取自定义属性也可以重新赋值,若赋值的自定义属性不存在时则自动添加

<a :data-categoryName="c1.categoryName"  >{{c1.categoryName}}</a>

三级联动的路由跳转

事件委派

将子标签的点击事件全部委托给父标签div

待解决问题

1.事件委派是把全部子节点【h1,dt,dl,em】的事件都委派给父亲节点

2.点击a标签时,才会跳转,怎么保证点击的是a标签

3.若点击的是a标签,如何区分是几级分类的标签

解决

使用自定义属性

 <a :data-categoryName="c1.categoryName" :data-category1id="1" >{{c1.categoryName}}</a>
 <a :data-categoryName="c2.categoryName" :data-category2id="2">{{c2.categoryName}}</a>
 <a :data-categoryName="c3.categoryName" :data-category3id="3">{{c3.categoryName}}</a>

传参时

 goSearch(event){
            
            let {categoryname,category1id,category2id,category3id} = event.target.dataset
            console.log(event.target.dataset)
            if(categoryname){
                let location ={name:'sousuo'}
                let query ={categoryName:categoryname}
                if(category1id){
                    query.category1Id = category1id
                }
                else if(category2id){
                    query.category2Id = category2id
                }
                else{
                    query.category3Id = category3id
                }
                location.query = query
            this.$router.push(location)
            }
        }

过度动画

前提:组件|元素务必要有v-if|v-show指令才能进行过度动画

包裹标签

<transition name="sort">
	.....
</trainsition>
<style>
.sort-enter{                          //进入动画
                opacity: 0;
                transform: translateX(-100px);
            }
            .sort-enter-active{
                transition: all 0.5s;
            }
            .sort-enter-to{
                opacity: 1;
                transform: translateX(0);
            }
</style>

mock(模拟) 数据

需要插件mockjs

生成随机数据,拦截Ajax请求

使用步骤:

1)在项目当中src文件夹中创建mock文件夹

2)准备JSON数据,mock文件夹中创建相应JSON文件—一定要格式化(留有空格跑不起来)

3)把mock数据所需要的图片放置到public文件夹下【public文件夹在打包的时候,会把相应的资源原封不动的打包到dist文件夹中】

注意:默认根目录是public,所以mock中图片路径写“/images/name.png”

4)开始mock虚拟数据了,通过mockjs模块实现,在mock文件夹下创建mockServer.js

5)mockServe在入口文件中引入(至少执行一次,该文件不需要暴露)

代码:

在mockServe.js中

//先引入mockjs模块
import Mock from 'mockjs';
//引入mock数据
//webpack默认对外暴露的:图片,json数据格式
import banner from './banner.json';
import floor from './floor.json';
//mock数据:第一个参数:请求路径,第二个参数:请求方式,第三个参数:请求数据
Mock.mock('/mock/banner',{code:200,data:banner});
Mock.mock('/mock/floor',{code:200,data:floor});

注意:

1)webpack默认对外暴露的:图片,JSON数据格式,不用export暴露

2)请求路径:“/mock/name”,没有“·”

在main.js中

//引入mockServer
import '@/mock/mockServer'

在api中配置接口,写一个mockAjax.js文件,跟之前的request.js一样,但baseURL不一样,使用“/mock”

import axios from 'axios'
//引入进度条
import nprogress from 'nprogress'
//引入进度条样式
import 'nprogress/nprogress.css'
const request = axios.create({
    baseURL: "/mock",
    timeout: 5000,
})
// 请求拦截器
request.interceptors.request.use(config => {
    //显示进度条
    nprogress.start();
    return config});
request.interceptors.response.use(response => {
    //隐藏进度条
    nprogress.done();
    return response.data},(error) => {
    return Promise.reject(new Error(error.message));
    })
export default request

在api下index.js中写接口调用函数

import mockRequest from "./mockAjax";
//对外暴露一个函数,只要调用这个函数,就向后台发送Ajax请求,获取数据,切记要返回值
export const reqBannerList = () => {return mockRequest({url: '/banner',method: 'get' })};

在要使用获取数据的组件中挂载:

mounted(){
        //派发action,通过vuex发起Ajax请求,将数据存储在仓库store中
        this.$store.dispatch('getBannerList')
    }

在store中配置相应的action,mutation

1)引入函数

import { reqCategoryList,reqBannerList } from "@/api";

2)在action中配置getBannerList函数

async getBannerList({commit}){
        let result=await reqBannerList()
        if  (result.code===200){
            commit('BANNERLIST',result.data)
        }
    }

3)在mutation中配置BANNERLIST函数,当然state中要有bannerList数组

BANNERLIST(state,data){
        state.bannerList=data
    },

4)在要使用获取数据的组件中获取数据:

    computed: {
        ...mapState({
            bannerList: state => state.home.bannerList
        })
    },

轮播图swiper

1)引包(相应的js|css

2)页面中结构务必要有

3)new swiper实例(轮播图添加动态效果)

// import Swiper bundle with all modules installed
import Swiper from "swiper/bundle";

// import styles bundle
import "swiper/css/bundle";

使用看官网

注意:最完美解决方案,解决轮播图问题 watch+nextTick: 数据监听 :监听已有数据的变化

watch 监听:可以保证数据一定ok,但不能保证v-for遍历结构是否完事

$nextTick

$nextTick:在下次DOM更新 循环结束之后 执行延迟回调。在 修改数据之后,立即使用这个方法,获取更新后的 DOM。

$nextTick:可以保证页面中的结构一定是有的,经常和很多插件一起使用【都需要DOM存在了】

watch监视bannerList

watch: {
    //方式2:watch + nextTick
    bannerList: {
      handler(newValue, oldValue) {
        this.$nextTick(() => {
          var swiper = new Swiper(".swiper", {
            // Optional parameters
            direction: "horizontal",
            loop: true,
            //分页器可点击
            paginationClickable: true,

            // If we need pagination
            pagination: {
              el: ".swiper-pagination",
            },

            // Navigation arrows
            navigation: {
              nextEl: ".swiper-button-next",
              prevEl: ".swiper-button-prev",
            },

            // And if we need scrollbar
            scrollbar: {
              el: ".swiper-scrollbar",
            },
          });
        });
      },
    },
  },

组件间通信方式

六种主要:

1.props:用于父子组件通信

用 :list='floor’传递

在父组件中

<Floor v-for="(floor,index) in floorList" :key="floor.id" :floor="floor"/>

在子组件中

props:['floor']

注意:props中写键,并且打引号

2.全局事件总线:$bus 全能

在main.js中注册$bus
new Vue({
  render: h => h(App),
  //全局注册事件总线 
  beforeCreate(){
    Vue.prototype.$bus = this
  },
  router,
  //注册store
  store
}).$mount('#app')
使用事件总线:
  1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

    methods(){
      demo(data){......}
    }
    ......
    mounted() {
      this.$bus.$on('xxxx',this.demo)
    }
    
  2. 提供数据:this.$bus.$emit('xxxx',数据)

  3. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

3.自定义事件:@on@emit 可以实现子给父通信

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>
    2. 第二种方式,在父组件中:
    <Demo ref="demo"/>
    ......
    mounted(){
       this.$refs.xxx.$on('atguigu',this.test)
    }
    
    1. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
    2. 触发自定义事件:this.$emit('atguigu',数据)
    3. 解绑自定义事件this.$off('atguigu')
    4. 组件上也可以绑定原生DOM事件,需要使用native修饰符。
    5. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
  • pubsub-js:vue当中几乎不用 全能
  • 插槽
  • vuex

vue 模块字符串

基础用法${}用``包裹起来

method:{
	demo(trademark){
     	 this.searchParams.trademark=`${trademark.tmId}:${trademark.tmName}`
     	 this.getDate()
    	}
}

动态样式

用 :class={‘样式’:true/false} 形式

<span v-show="isOne" class="iconfont" :class="{'icon-up':isAsc,'icon-down':isDesc}"></span>

分页器

一般使用Element-ui超级简单

分页器展示需要的数据

pageNo:当前第几个

pageSize:代表每一页展示多少条数据

total:代表整个分页一共要展示多少条数据

continus:代表分页连续页码个数

触发事件

分页器点击页数,触发事件,父组件进行展示商品

自定义事件:

分页器中:

  methods: {
    /* 
    将当前页码改为指定页码
    */
    changeCurrentPage (page) {
      // 修改当前页码
      this.mcPage = page
      // 通知外部父组件
      this.$emit('currentChange', page)
    }
  },

父组件中:

<Pagination :currentPage="searchParams.pageNo" :pageSize="searchParams.pageSize" :total="total" @currentChange="currentChange" />
  methods: {
    currentChange(page){
      this.searchParams.pageNo=page;
      this.getDate()
    },

放大镜

需要:蒙版,左边一个div放正常照片,右边一个div放放大的照片,右边默认是隐藏的

<template>
  <div class="spec-preview" ref="preview">
    <img :src="imgObj.imgUrl" />
    <div class="event" @mousemove="handler"></div>
    <div class="big" >
      <img :src="imgObj.imgUrl" ref="big"/>
    </div>
    <div class="mask" ref="mask"></div>
  </div>
</template>

其中,右边放的背景照片移动方向和蒙版反方向,*2是因为放大了两倍

methods:{
      handler(){
        let mask=this.$refs.mask;
        let big=this.$refs.big;
        let left=event.offsetX-mask.offsetWidth/2;
        let top=event.offsetY-mask.offsetHeight/2;
        if(left<0){
          left=0;
        }else if(left>this.$refs.preview.offsetWidth-mask.offsetWidth){
          left=this.$refs.preview.offsetWidth-mask.offsetWidth;
        }
        if(top<0){
          top=0;
        }else if(top>this.$refs.preview.offsetHeight-mask.offsetHeight){
          top=this.$refs.preview.offsetHeight-mask.offsetHeight;
        }
        mask.style.left=left+'px';
        mask.style.top=top+'px';
        big.style.top=-top*2+'px';
        big.style.left=-left*2+'px';
      }
    },
<style lang="less">
  .spec-preview {
    position: relative;
    width: 400px;
    height: 400px;
    border: 1px solid #ccc;

    img {
      width: 100%;
      height: 100%;
    }

    .event {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 998;
    }

    .mask {
      width: 50%;
      height: 50%;
      background-color: rgba(0, 255, 0, 0.3);
      position: absolute;
      left: 0;
      top: 0;
      display: none;
    }

    .big {
      width: 100%;
      height: 100%;
      position: absolute;
      top: -1px;
      left: 100%;
      border: 1px solid #aaa;
      overflow: hidden;
      z-index: 998;
      display: none;
      background: white;

      img {
        width: 200%;
        max-width: 200%;
        height: 200%;
        position: absolute;
        left: 0;
        top: 0;
      }
    }

    .event:hover~.mask,
    .event:hover~.big {
      display: block;
    }
  }
</style>

浏览器存储

本地存储:

持久化存储

localStorage.setItem('uuid_token',uuid)

会话存储:

非持久化存储,关闭浏览器就没了

sessionStorage.setItem('uuid_token',uuid)

游客获取数据

在src文件夹下新建utils文件夹

在uuid_token.js中

import { v4 as uuidv4 } from 'uuid';
export const getUUID = () => {
    let uuid=localStorage.getItem('uuid_token')
    if(!uuid){
        uuid=uuidv4()
        localStorage.setItem('uuid_token',uuid)
        
    }
    return uuid
}

在商品详情页的store中

import { getUUID } from '@/utils/uuid_token'
const state = {
  detailInfo:{}, // 商品详情信息 
  uuid_token:getUUID(), // 商品sku相关信息对象  
}

在api文件夹下的request.js中

在请求拦截器中

    //请求头添加一个字段(userTempId): 临时用户标识,事先和后台老师约定好的,不是固定的
    if(store.state.detail.uuid_token){
        config.headers.userTempId = store.state.detail.uuid_token
    }

Token

定义:用户令牌,由服务器派发给用户的唯一标识

储存在vuex中,然后在发送axios请求时,在请求拦截器中,将token赋值给config.headers.token

本地存储token

在utils文件夹下新建token.js文件

export const setToken = (token) => {
    localStorage.setItem('token_key', token);
}
export const getToken = () => {
    return localStorage.getItem('token_key');
}
export const removeToken = () => {
    localStorage.removeItem('token_key');
}

在store中的user文件夹下

const state = {
    code: '',
    token: getToken(),
    userInfo: {},
}
const mutations = {
    MUTATE_Token(state, data) {
        state.token = data;
        setToken(data)
    },
}
 const actions={
     async userLogin({ commit }, userInfo) {
        const result = await reqLogin(userInfo);
        if (result.code === 200) {
            console.log("登录成功",result.data);
            commit('MUTATE_Token', result.data.token);
            return 'ok';
        } else {
            console.log("登录失败",result.data);
            return Promise.reject(new Error('failed'));
        }
 }

在 api文件下request.js中

import store from '@/store'
// 请求拦截器
request.interceptors.request.use(config => {
    //需要携带token的请求
    if(store.state.user.token){
        config.headers.token = store.state.user.token
    }
    //显示进度条
    nprogress.start();
    return config}
    );

登录后在detail中挂载一个函数,获取用户信息


axios同步异步请求

//同步
async init(id) {
	await this.initA()
	await this.initB(id)
},

initA(){
//先执行A成功,再执行B
}
initB(){
//先执行A成功后,再执行B
}
//异步
init(id){
	this.initA()
	this.initB()
}
initA(){
//同时执行A和B
}
initB(){
//同时执行A和B
}

组件使用api

在main.js中引入api,将其赋给Vue的原型

注意:vue的原型===vc的原型的原型,vc是vue原型的实例

//引入api
import * as API from '@/api'
new Vue({
  render: h => h(App),
  //全局注册事件总线 
  beforeCreate(){
    Vue.prototype.$API = API
  },
  router,
  //注册store
  store
}).$mount('#app')

element-ui

安装

推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。

npm i element-ui -S

安装 babel-plugin-component:

npm install babel-plugin-component -D

在bable.config.js中

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

使用

在main.js中引入

import { Button, Select } from 'element-ui';
//引入element样式
import 'element-ui/lib/theme-chalk/index.css';

注册组件

三种方式:

1.注册为全局组件

Vue.component(Button.name, Button);
Vue.component(Select.name, Select);

2.直接use

Vue.use(Button)
Vue.use(Select)

3.挂在原型上

使用于特定的一些组件

Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值