1.项目文件vueCli3.0下:
    pulic文件下:favicon.ico是网址上方标题的的小图标。
    index.html:是入口文件。
    src:项目的主文件:
        assets:是存放静态资源(如,图片,css等)的文件。
            img:存放图片文件。
            iconfont:图标字体文件。
        components:可复用的组件。
        views:页面。
        api:项目的ajax请求请求。
        config:项目的配置文件。
            index.js:配置,在需要的地方import config  from "./config/index.js"引入配置对象即可。
        directive:存放vue的自定义指令。
            index.js:
        lib:
            tools.js:存放与业务无关的,纯粹的工具方法。
            util.js:存放与业务结合有关的。
        router:存放路由有关的,将router.js移入该文件内。
            index.js: 存放引入文件,配置路由实例。
            router.js: 单独存放处理路由文件,配置路由列表。
        store: 存放状态管理的文件。store.js移入到该文件内,修改为index.js。记得修改main.js的入口文件
            index.js:
            mutations.js:
            import getters from "./getters"   //相当于计算属性,对state参数的计算
            state.js:
            actions.js:
            mudels:存放模块文件。
                user.js:如存放用户的登录信息        
        mock:  模拟返回的数据,在后台接口还么有完成,前端通过模拟数据。  npm install mockjs -D下载 ,import Mock from "mockjs"引入
            index.js: import Mock from "mockjs"引入        
    vue.config.js:自定义设置文件的配置,如跨域请求地址,简写src为@,设置项目的基本路径。
            
2. vscode编译器的:添加配置编译器的文件:
    在src同级下.editorconfig:
        root=true
        [*]     //表示该编译器配置针对所有文件
        charset=utf-8
        indent_style=tabs  缩进键
        indent-size=2     缩进的大小        
    然后在编译器中安装editorConfig for VS Code,然后就可运行添加的配置编译器的文件了
    
    
3. router-link 是封装了的a标签。router-view渲染路由视图,两者效果一样。
命名路由:即路由有name属性name: 'home',<router-link to="/about"></router-link> 相当于命名路由 <router-link :to="{name:'about'}"></router-link>
    3.1 配置路由列表的5种方法:
        a.import Home from './views/Home.vue',如果有 name: 'home',表示命名路由
            {
              path: '/',
               alias:'/home_page',  //别名,即访问"/home_page"和访问"/"和通过name:"home",访问的效果是一样的
              name: 'home',
              component: Home    //普通写法
            },
             {
              path: '/home1',
              name: 'home1',  //命名路由
            },
        b.这样写,有懒加载的作用,即该页面显示时才会加载。不需要import Home from './views/Home.vue'。
            {
              path: '/about',
              name: 'about',
              component: () => import('./views/About.vue')  
            },
        c.高级写法,动态加载路由,name是参数,{{$route.params.name}}调用参数name的值。
            {
              path: '/argu/:name',
              props:true,             //表示允许组件props:{}中接受name参数值,然后可以直接渲染在页面{{name}}
              name: 'argu',
              component: () => import( './views/argu.vue')  
            },
        d.嵌套路由。 <div class="parent"> <router-view/> </parent>  
            {
                 path: '/parent',    //嵌套路由
              component: () => import('./views/Argu.vue'),
              children:[
                  {
                      path:"child1",   //注意只有父级需要'/'
                      component: () => import( './views/child1.vue'),
                  },
                  {
                      path:"child2",
                      component: () => import('./views/child2.vue'),
                  },
              ]
            },
        e. 命名视图:同时存在多个路由跳转时<router-view/> <router-view name="email"/> <router-view name="tel"/> 
            {
              path: '/name_router',
              components: {
                  default:() => import('./views/about.vue') ,   //如果<router-view/> 没有name属性值,默认对应该路由
                  email:() => import('./views/parent.vue') ,    //<router-view name="email"/> 对应该路由
                  tel:() => import('./views/argu.vue')       //<router-view name="tel"/> 对应该路由
              } 
            },
        f. 重定向:重新定义跳转的路径,即本来是访问 '/home',重新绑定跳转到"/"
            {
              path: '/home',
              redirect:"/",   //3种重定向的方法
//              redirect:{
//                  name:"home1"
//              },
//               redirect:to =>{    //如根据参数确定跳转到哪个页面
////                  console.log(to)
////                return "/"
//                return {
//                    name:"home1"
//                }
//              },
              
            },            
 4. js操作路由(即编程式的导航): 
    a. 返回/前进一页:返回:this.$router.go(-1)、this.$router.back()。前进:this.$router.go(1)。
    b. 跳转到其他页:
        this.$router.push("/parent")。
        this.$router.push({name:"parent",query:{name:"ace"}),即浏览历史纪录保存着,query是参数。
        this.$router.push({path:`/argu/${name}`})    ,es6带参数跳转,针对 path: '/argu/:name',该路由。
        this.$router.push({path:"/parent",params:{name:"ace"}) , 带参数跳转。
    c. 用其他页替换本页:this.$router.replace("/about")或this.$router.replace({name:"parent"}),即浏览历史纪录没有了。
   

5. 路由传值:
    5.1 基于动态匹配的页面(path: '/argu/:name')传值。
        {
            path: '/argu/:name',
            props:true,             //表示允许Argu.vue组件中props:{}中接受name参数值,然后可以直接渲染在页面{{name}}
            component: () => import( './views/argu.vue')  
        },
    5.2 基于普通页面传参,对象模式传参。
        {
            path: '/about',
            props:{
                food:"香蕉"
            },                      //表示允许about.vue组件中props:{}中接受food参数值,然后可以直接渲染在页面{{food}}
            component: () => import( './views/argu.vue')  
        },
    5.3 基于普通页面传参,函数模式传参。
        {
            path: '/parent',
            props: route=>{
                return {
                    food:route.query.food
                }
            },                      //表示允许parent.vue组件中props:{}中接受food参数值,然后可以直接渲染在页面{{food}}
            component: () => import( './views/argu.vue')  
        }

6. 导航守卫:如根据是否登录或登录者的权限跳转不同的页面,
    6.1 全局守卫:即在全局设置一个守卫。在router/index.js中配置全局守卫
        const router=new  Router({
            routes
        })    
        const IS_LOGIN=true   //是否登录的判断        
        router.beforeEach((to,form,next)=>{  //router实例的beforeEach方法是注册一个全局前置守卫,从from路由对象到to路由对象,
            if(to.name !=="login"){    //如果即将跳转的页面不是登录页面
                if(IS_LOGIN) {
                    next()      //如果已即登录,就直接跳转
                }else{
                    next({name:'login'})    //如果没有登录,就跳转到登录页面
                } 
            }else{   //如果即将跳转的页面是登录页面
                if(IS_LOGIN) {
                    next({name:'home'})      //如果已即登录,就直接跳转首页,{name:'home'}也可是'/home'
                }else{
                    next()    //如果没有登录,就直接跳转
                } 
            }
        })    
        router.beforeResolve((to,form,next)=>{  //router实例的beforeResolve方法是注册一个全局守卫,从from路由对象到to路由对象,即页面跳转前所有钩子执行完最后执行该函数 ,
        
        })        
        router.afterEach((to,form)=>{  //router实例的afterEach方法是注册一个全局钩子,从from路由对象到to路由对象,即页面跳转之后执行,
            //loading=false
        })
    6.2 组件守卫:即该组件独有的守卫。    在router/router.js中配置组件守卫        
        {
          path: '/',
          component: Home,    //普通写法
          beforEnter:(to,from,next)=>{   //该组件独有的守卫
              if(from.name="login"){
                  alert("这是从登陆页面跳转过来的")
              }else{
                  alert("这不是从登陆页面跳转过来的")
              }
              next()   //一定要在最后执行next(),否则不会跳转
        },
    6.3  在组件里面的3种守卫,如在login.vue组件里面:
        a.beforeRouteEnter:即将跳转到当前页面,但是页面还没有渲染,所有里面的this不指向实例vue该组件
            beforeRouteEnter(to,from,next){   
                console.log(to.name)
                next(vm=>{
                    console.log(vm)      //而这里的vm就是该组件的实例了。
                })
            }
        b.beforeRouteLeave:即将离开当前页面时执行,如即将离开编辑页面,弹出提醒框,提醒你是否保存编辑内容。
            beforeRouteLeave(to,from,next){     //此时组件是已经渲染了,this可以执行vue实例
                const leave=confirm("你确定要离开本页面么?")
                if(leave){next()}
                else{next(false)}    //false表示不发生页面跳转
            }
        c.beforeRouteUpdate:即路由发生改变,组件(复用组件)被复用时,执行。如同一个页面,在url上修改了参数之后,该页面被复用了,就会执行
            beforeRouteUpdate(to,from,next){   //此时组件是已经渲染了,this可以执行vue实例
                console.log(to.name)
            }
    注意:整个导航守卫的流程:
        a. 导航被触发:即url路由地址发生改变。
        b. 在失活的组件:即将离开的页面组件,里调用离开守卫函数(beforeRouteLeave)。
        c. 调用全局的前置守卫:即函数beforeEach。
        d0. 如果跳转的是重/复用的组件里调用:在复用/重用的组件里调用函数beforeRouteUpdate。
        d1. 如果跳转的是新的组件调用:在新的组件里调用beforeRouteEnter。
        e. 调用路由独享的守卫:即router/router.js里面的函数beforEnter 。
        f. 解析异步路由组件:
        g. 在被激活的组件里(即将进入的页面):调用beforeRouteEnter。
        h. 调用全局的解析守卫:即调用beforeResolve。
        i. 导航被确认。
        j. 调用全局的后置守卫:afterEach。
        k. 触发DOM的渲染。
        l. 用创建好的实例调用beforeRouteEnter守卫传给next()的回调函数。

7. 通过页面组件的meta:字段设置每个页面的window.document.title标题。
    如在login.vue组件中:
        meta:{   //与生命周期平级。
            title:"我是登录页面标题"
        }
    然后在router/index.js的beforeEach中设置,import {setTitle} from "@/lib/util.js"
        to.meta.title && setTitle(to.meta.title)
    在lib/util.js中
        export const setTitle =(title)=>{
            window.document.title=title ||  "vue-cli3"
        }
8. 设置路由跳转时的动画效果:
    8.1 静态设置动画效果:
        <transition-group name="router">   //一组路由视图,设置动画效果,必须写key值。然后在css中设置.router-enter/leave-to/active样式。
            <router-view key="default"/>   
            <router-view key="email"/>
            <router-view key="tel"/>
        </transition-group>
    8.2 动态设置动画效果:
        <transition-group :name="transitionName">   //一组路由视图,设置动画效果,必须写key值。然后在css中设置.router-enter/leave-to/active样式。
            <router-view key="default"/>   
            <router-view key="email"/>
            <router-view key="tel"/>
        </transition-group>
        data(){
            return{
                transitionName:""
            }
        },
        watch:{
            "$route" (a){   //a表示当前页面,表示如果在url传入参数transitionName="router",则a.query.transitionName='router'
                a.query &&  a.query.transitionName && (this.transitionName =a.query.transitionName)
            }
        }

9. 父组件与子组件的传值:
    9.1 父传值给子组件:props传值
        父组件:
            <div class="parent">
                <son-assembly :sendVal="value"></son-assembly>
            </div>
        
        子组件:
            <div class="son">
                {{value}}
            </div>
            props:{
                son:{
                    type:[String,Number],
                    default:"123"
                }
            }        
    9.2 子传值给父组件:自定义事件传值
        子组件:
            <div class="son"></div>
            this.$emit("aceHandle",val)
        父组件:
            <div class="parent"  @aceHandle="myHandle"></div>
            myHandle(val){
                console.log("这是自定义事件传值",val)
            }
        注意:在vue中@input="inputHandle" 表示input输入值改变时触发的内置事件。inputHandle(e){console.log("输入框的值是",e,target.val)}

10.bus传值,状态管理:bus即空的vue实例,如用于简单场景下的兄弟组件之间传值。
    10.1 src下创建bus/index.js文件。
        import Vue from "vue"
        const Bus=new Vue()
        export default Bus
    10.2 在main.js引入bus,并添加到vue的原型对象里,然后在任何地方都可以不需要在引入,直接使用this.$bus.
        import Bus from './bus/index.js'
        Vue.prototype.$bus=Bus
    10.3 从兄弟组件A传值给兄弟组件B:
        A组件:
            this.$bus.$emit("myHandle",val)
        B组件:
            mouted(){
                this.$bus.$on("myHandle",(val)=>{  //监听自定义事件myHandle
                    //在这里处理接收到B组件传递过来的值
                })
            }

11. vuex传值,状态管理:src下创建store文件用于vuex状态管理
    11.1 index.js入口文件的管理: 然后在main.js中引入import store from './store/index.js',然后全局设置new Vue({store}).$mount('#app')
        import Vue from 'vue'
        import Vuex from 'vuex'
        import state from "./state"      //全局状态参数管理
        import getters from "./getters"   //相当于计算属性,对state参数的计算
        import mutations from "./mutations"   
        import actions from "./actions"   
        import user from "./mudule/user.js"    //单独某个模块如用户模块user的状态管理
        
        Vue.use(Vuex)
        
        export default new Vuex.Store({
          state ,   //es6语法相当于state:state
          getters,
          mutations ,
          actions,
          mudules:{
              user
          }
        })
    11.2 state.js全局状态参数管理: 
        定义全局参数:
            const state={
                appName:"我是全局参数,在组件内都可传递值"
            }
            export default state
        调用全局参数值:
            方法1:
                在某个组件内{{this.$store.state.appName}}就可获取该值了,或通过可在该组件写入到计算属性中computed
                computed:{
                    appName(){
                        return this.$store.state.appName
                    }
                }
                <p>{{appName}}</p>
            方法2:
                import {mapState} from "vuex"
                computed:{
                    ...mapState(["appName"])  //这2种写法一样。...表示展开一个对象。
//                    ...mapState({
//                        appName:state=>state.appName
//                    })
                }
                <p>{{appName}}</p>
    11.3 user.js 获取模块中user.js里面的状态参数管理:
        定义单独某个模块中全局参数:
            const state={
                userName:"我是user模块的参数值"
            }
            const mutations={}
            const actions={}
            export default{
                state,
                mutations,
                actions
            }        
        调用单独某个模块全局参数值:
            方法1:
                在某个组件内{{this.$store.state.user.userName}}就可获取该值了,或通过可在该组件写入到计算属性中computed
                computed:{
                    userName(){
                        return this.$store.state.user.userName
                    }
                }
                <p>{{userName}}</p>
            方法2:
                import {mapState} from "vuex"
                computed:{
                    ...mapState(["userName"])  //这3种写法一样。...表示展开一个对象。
//                    ...mapState({
//                        userName:state=>state.user.userName
//                    })
//                    ...mapState("user",{        //传入模块名
//                        userName:state=>state.userName
//                    })
                }
                <p>{{userName}}</p>
                
            注意:在模块状态管理中如果有命令空间,即
                export default{
                    namespaced:true,   //设置命名空间为true,使得模块更加密闭,不受到外界的干扰
                    state,
                    mutations,
                    actions
                }
            方法3:
                import {createNamespacedHelpers} from "vuex"
                const {mapState}=createNamespacedHelpers("user")    //参数user是命令空间的名称(模块名,user.js)
                computed:{
                    ...mapState(["userName"])  //这2种写法一样。...表示展开一个对象。
//                    ...mapState({              //不许要在传入模块名了
//                        userName:state=>state.userName  
//                    })
                }
                <p>{{userName}}</p>
    
    11.4 getters.js相当于组件的computed计算属性,是对state状态的计算处理。 在模块如user.js中使用getters和使用state方法一样
        定义getters(计算属性):
            const getters={
                appNameVersion:(state)=>{    //依赖于state.js
                    return state.appName+"v2.0"
                }
            }
            export default getters
        调用getters(计算属性的结果):
            方法1:
                在某个组件内{{this.$store.getters.appNameVersion}}就可获取该值了,或通过可在该组件写入到计算属性中computed
                computed:{
                    appNameVersion(){
                        return this.$store.getters.appNameVersion
                    }
                }
                <p>{{appNameVersion}}</p>
            方法2:
                import {mapGetters} from "vuex"
                computed:{
                    ...mapGetters(["appNameVersion"])  //这3种写法一样。...表示展开一个对象。
//                    ...mapGetters({
//                        userName:state=>state.appNameVersion   
//                    })
                }
                <p>{{appNameVersion}}</p>
    
    11.5 mutations.js修改state状态参数的值;
        在mutations定义修改state的事件:
            import vue from "vue"
            const mutations={
                set_app_name(state,params){    //state表示store/state.js,params是要修改state状态中参数的新值,可能是对象,或字符串
                    state.appName=params      //参数时字符串
            //        state.appName=params.appName    //参数时对象
                },
                set_app_version(state){     //如果stata.js中没改属性参数,这个表示给state.js中添加version并赋值v2.0
                    vue.set(state,"version","v2.0")    
                }
                
            }
            export default mutations
        在组件里调用上面定义的事件:
            方法1:
                this.$store.commit("set_app_name","我是state.js里新修改的appName的值")  //参数是字符串
                this.$store.commit("set_app_name",{appName:"我是state.js里新修改的appName的值"})  //参数是对象
                this.$store.commit({type:"set_app_name",appName:"我是state.js里新修改的appName的值"})  //参数是对象,且事件也包含在对象里
            方法2:
                在组件的方法里
                    import {mapMutations} from "vuex"
                    methods(){
                        ...mapMutations([
                            "set_app_name",
                            "set_app_version"
                        ]),
                        Handle(){
                            this.set_app_version("newAppName");
                            this.set_app_name()
                        }
                    }
        注意:mutations和getters和actions在模块里面是在模块里且没有命令空间限制,
            会默认将模块中的mutations和getters和actions注册在全局store文件下的mutations.js和getters.js和actions.js,如下写,且不需要传入模块名,如"user"
                        ...mapMutations([
                            "set_app_name",
                            "set_app_version"
                        ]),    
            但是如果有命令空间限制namespaced:true,   //设置命名空间为true,使得模块更加密闭,不受到外界的干扰
                        ...mapMutations("user",[    //需要传入模块
                            "set_app_name",
                            "set_app_version"
                        ]),    
                        
                        
                        
    11.6 action.js异步修改state.js的状态值,如通过获取后台数据,将state.js的值修改成后台获取的数据:
        定义异步修改状态值的方法:
            import {getAppName} from "@/api/app.js"
            const action={   //异步操作状态的改变,如通过接受接口的api返回的数据,从而改变state.js的状态值
            //    updateAppName({commit}){   //es6写法:{commit},相当于func(obj){const commit=obj.commit}
            //        getAppName().then(res=>{
            //            console.log(res)
            ////            const {info:{appName}}=res;   //es6的
            ////            commit("set_app_name",appName);
            //            commit("set_app_name",res.info.appName);   //通过commit关联mutations.js中的是set_app_name()方法,从而异步修改state.js状态值
            //        }).catch(err){
            //            console.log(err)
            //        }
            //    }
                async updateAppName({commit}){   //es8的语法,与上面执行结果一样,只是将异步变成同步。
                    try{
                        const {info:{appName}} =await getAppName()
                        commit("set_app_name",appName);
                    }catch(err){
                        console.log(err)
                    }
                }
            
            }
            export default action

        调用异步修改的状态值的方法:
            方法1:
                import {mapAction} from "vuex"
                    methods(){
                        ...mapAction([
                            "updateAppName"
                        ]),
                        Handle(){                
                            this.updateAppName()
                        }
                    }            
            方法2:
                this.$store.dispatch("updateAppName",val)
    11.7 在模块中定义    action方法        
        user.js        
            const state={}
            const mutations={}
            const actions={
                updateUserName({commit,state,rootState,dispatch}){    //commit用于提交到mutation,state值当前文件下state,rootState值store文件夹下state.js
                    rootState.appName
                }
            }
            export default{
                state,
                mutations,
                actions
            }    
    11.8 api/app.js模拟后台接口返回数据:
        export const getAppName=()=>{
            return new Promise((resolve,reject)=>{
                const err=null;
                setTimeout(()=>{  //模拟接口操作请求
                    if(!err) resolve({code:200,info:{appName:"newAppName"}})
                    else reject(err)
                })
            })
        }

12. vuex进阶-store插件----持久本地存储:
    新建文件:store/plugin/saveInLocal.js
        //定义一个持久化存在在本地的state状态管理的插件,即使每次刷新,也不会影响修改后的值
        export default state=>{
            console.log('store初始化时执行该函数');
            if(localStorage.state){store.replaceState(JSON.stringify(localStorage.state))}  //如此本地已经存储了,每次刷新页面(即初始化store时),
                                                                                //就用mutation提交后的本地存储替换提交前的
            store.subscribe((mutation,state)=>{
                console.log("每次有提交mutation时就执行");  //每次提交mutation时,时都将state值存储在本地
                localStorage.state=JSON.stringify(state);  //state 是一个对象,转换为json字符串,存储在本地
            })
        }
    在store/index.js中:
        import saveInLocal from './plugin/saveInLocal.js' 
        export default new Vuex.Store({
          state ,   //es6语法相当于state:state
          mutations ,
          getters,
          actions,
          mudules:{
              user
          },
          plugins:[saveInLocal]      //加载插件
        })
13. store下的严格模式:在严格模式下,不能直接修改state里面的值(this.$store.state.user.userName="newName"),需要在mutation提交中修改,否则会报错(虽然也会修改)
    在store/index.js下:
        export default new Vuex.Store({
          strict:true,    //是否开启严格模式,process.env.NODE_ENV ==="devalopment"    ,在开发环境下是严格模式,否则不是
          state ,   //es6语法相当于state:state
          mutations ,
          getters,
          actions,
          mudules:{
              user
          },
          plugins:[saveInLocal]      //加载插件
        })

14. v-model:如果绑定的属性不是组件data(){return{} }里面的属性,也是state里面的属性,就存在问题,因为state里面的属性时需要在mutation中修改。
    v-model:的本质就是:在组件上绑定一个属性传值,再绑定一个@input事件监听,当输入的值有变化时,就直接替换掉原来的值,
    解决双休绑定state值的方法:
        方法1:<input   :value="stateVal" @input="changeStateVal"/>
        ...mapMutations({"SET_STATE_VALUE"})
        changeStateVal(val){
            this.SET_STATE_VALUE(val)   //在mutations.js中设置:SET_STATE_VALUE(state,val){state.stateVal=val} ,在state.js中设置stateVal:"abc"
        }
        方法2:<input   v-model="stateVal"/>
        ...mapMutations({"SET_STATE_VALUE"})
        computed:{
            stateVal:{   //计算属性里stateVal是对象不是方法,有set()和get()方法
                get(){
                    return this.$store.state.stateVal;
                },
                set(val){
                    this.SET_STATE_VALUE(val)
                }
            }
        }
        
15. ajax请求:
    15.1解决跨域问题:
        方法1:在vue.config.js里面设置跨域代理请求:
             devServer:{       //设置跨域,即将本文件内任何没有匹配到的静态文件,都指向跨域地址http://localhost:4000
                 proxy:'http://localhost:4000'
             }
             在发送axios请求里执行:
             axios.post("/login",{uname:"Ace",upwd:"1234"}).then(data=>{})
        方法二:
             在发送axios请求里执行:
             axios.post("http://localhost:3000/login",{uname:"Ace",upwd:"1234"}).then(data=>{})
             在后台(如node的app.js)设置跨域:
             app.all("*",(req,res,next)=>{   //*代表所有请求。
                 req.header("Access-Contral-Allow-Origin","*");
                 req.header("Access-Contral-Allow-Headers","X-Requested-Width,Content-Type");
                 req.header("Access-Contral-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
                 next();
             })
    15.2 封装axios:
        15.2.1 请求/响应拦截:
            创建文件lib/axios.js:
                import axios from "axios"
                import {baseURL} from "@/config/index.js"
                class HttpRequest{  //es6的类的封装
                    constructor(baseUrl=baseURL){   //类的必须方法,如果没有主动添加,在类里会自动添加一个空的该方法,当new HttpRequest(参数时),该参数就是constructor的参数
                        this.baseUrl=baseUrl;      //baseUrl=baseURL是es6的默认传参
                        this.queue={},  //一个空对象,用于存放每一次请求的url
                    }
                    getInsideConfig(){  //设置全局config配置
                        const config={
                            baseUrl:this.baseUrl,
                            headers:{
                                //
                            }
                        }
                        return config
                    }
                    interceptors(instance,url){  //axios拦截器方法 ,参数axios的实例
                        instance.interceptors.request.use(config=>{    //请求拦截器,config是发送请求时的配置参数        
                            if(Object.keys(this.queue).length){  //判断this.queue队列是否有请求的url,Object.keys是获取一个对象的所有的key值
                                //添加一个全局的loding....,如iview中的spin的加载效果标签。
                            }
                            this.queue[url]=true;  //设置queue对象的key值
                            console.log(config)
                            return config;
                        },error=>{    //error是请求错误时,返回的错误信息
                            return Promise.reject(error)
                        })
                        instance.interceptors.reponse.use(res=>{    //响应拦截器,res是服务端响应返回的数据
                            //移除一个全局的loding....,如iview中的spin的加载效果标签。
                            delete this.queue[url]    //当请求成功了 ,就可以清除this.queue对列对于的值了
                            console.log(res)
                            return res;
                        },error=>{    //error是响应错误时,返回的错误信息
                            delete this.queue[url]    //当请求失败了 ,就可以清除this.queue对列对于的值了
                            return Promise.reject(error)
                        })
                    }
                    
                    request(options){    //options是创建请求的config配置,不是全局config配置
                        const instance=axios.create()    //axios.create()创建一个axios实例,参数是配置对象
                        options=Object.assion(this.getInsideConfig(),options)  //将俩个对象合并成一个对象,key相同的,后面的对象值覆盖前面的。
                        this.interceptors(instance,options.url);
                        return instance(options)
                    } 
                }
                export default HttpRequest

        15.2.2 在config/index.js配置基础信息:
            //用于存放项目的配置
            export const baseUrl=process.env.NODE.ENV==="production"
                    ?"http://www.ace.com"   //如果是开发环境,就写开发环境的接口
                    :" " //如果是在开发环境下,且已经设置了本地跨域代理 devServer:{ proxy:'http://localhost:4000'},
                        //这里设置空字符串,如果没有设置本地跨域代理这里就写'http://localhost:4000'
        15.2.3 在api/index.js实例化axios
            import HttpRequest from "@/lib/axios"
            const axios=new HttpRequest()  //创建一个HttpRequest实例
            export default axios
        15.2.4 在api/user.js中定义login.vue组件的登录接口:
            import axios from "./index.js"
            export default getUserInfo=({uanme})=>{
                return axios.request({
                    url:"/getUserInfo",
                    method:'post',
                    data:{      //post请求,参数写在data里面
                        uname:uname
                    }
                })
            }
        15.2.5 在login.vue组件里引入api/user.js中定义好的登录接口方法,然后调用:
            import {getUserInfo} from "@/api/user.js"
            getInfo(){
                getUserInfo({uname:"Ace"}).then(res=>{
                    console.log(res)
                })
            }
16. 组件的ID命名,插槽的实现,DOM获取,以及父组件调用子组件的方法:    
    子:
        <div>
            <slot name="slot1"></slot>
            <span :id="myId" ref="child"> 我是子组件</span>
            <slot name="slot2"></slot>
        </div>
        
    父:
        <div>
            <v-child ref="childSpan"></v-child>
        </div>    
        
        
    16.1 如何给组件命名id不会冲突其他组件的id名:this._uid在项目中,每个组件都有独一无二的_uid,给里面组件命名时,带上这个独一无二的_uid就会避免与其他组件命名冲突。
        computed:{
            myId(){
                return `child_${this._uid}`
            }
        }
    16.2 怎么获取子组件dom里面的内容(原生js获取和ref获取):
        ref获取:this.$refs.child.innerText
        原生js获取:document.getElementById(myId).innerText
    16.3 父组件怎么调用子组件的方法:
        this.$refs.childSpan.getChildInfo()
17. vue中操作dom元素:通过数据操作dom的width/height/top/bottom....
    17.1 通过数据操作dom的width/height/top/bottom....
        <div ref="div" :style={left:divLeft;width:`${divWidth}px` }>
            <span @mousedown="downHandle"></span>
        </div>
        computed:{
            divLeft(){
                return ``
            },
            divWidth(){
                return `clac(30%-4px)`   //css3的属性clac()计算出百分比和px的结果
            }
        }
    17.2 鼠标按下移动事件:
        downHandle(e){
            document.addEventListener("mousemove/mouseup",mousemoveHandle/mouseupHanlde) ;  //给doucment绑定鼠标移动、松开事件
            e.pageX   //是获取触发downHandle的是鼠标距离页面左边的距离
            this.$refs.div.getBoundingClientRect() ;  //返回ref='div'元素dom的width,height,top,bottom,right....等信息的对象。        
        }
18. 在组件引入外部css的2种方法:
        在script里面:import "../index.css"
        在style里面:@import "../index.css"
 

10-06 11:46