zoukankan      html  css  js  c++  java
  • vue11----前端优化、路由懒加载(异步组件)、keep-alive、localStorage二次封装、vue-lazyload图片懒加载、mint-ui、封装加载loading条、axios请求x-www格式的数据、nginx代理、路由守卫、mint-ui实现下拉刷新,上拉加载更多、自己封装过哪些组件和模块

    ### 优化

        1、加载速度的优化
            ①雪碧图---->base64、iconfont
            ②代码压缩
            ③图片视频压缩
            ④cdn缓存
            ⑤路由懒加载(异步组件) 首页引入的大文件进行分批次引入
        2、运行效率优化
            ①减少http请求,页面打开之后基本不涉及到数据更改
                <keep-alive include="['a','b']" exclude="['a','b']"></keep-alive>
     
                正常的组件切换的时候执行创建和销毁,加上keep-alive后,组件保存到缓存中,不会执行创建和销毁。
            
            ②数据本地化(localStorage session(可以用keep-alive代替) cookie)
                a、发起ajax前,先看一下本地缓存有没有,如果有就在缓存中取,如果没有再发起请求
                b、localStorage的二次封装
                    (1)考虑兼容问题
                    (2)简化读取与存储
                    (3)有时间限制
                c、图片懒加载
                    ui框架
                    插件:vue-lazyload
        3、用户体验优化
            ①加载体验
            ②加载的loading条

    ### 路由懒加载(异步组件)(router.js)

        原理:将每个组件都打成一个包,这样首页引入的大文件就进行分批引入。
     
        实现:将所有的同步组件引入方式改为异步组件引入方式。
            // import Recommend from "pages/Recommend.vue";
            // import Singer from "pages/Singer.vue";
            // import Detail from "pages/Detail.vue";
            // 改为路由懒加载方式引入:引入组件的方式从同步变为异步
            const Recommend=()=>import("pages/Recommend.vue");
            const Singer=()=>import("pages/Singer.vue");
            const Detail=()=>import("pages/Detail.vue");
        此时,npm run build后在dist/js中多一个 chunk-00e2fa9f.7be196b5.js 文件。注意:npm run build后dist/js中的map文件可以全部删除。

    ### <keep-alive></keep-alive>(App.vue)

        原理:<keep-alive>是vue的一个内置组件,被<keep-alive>包裹的组件,不会反复的经历创建与销毁,它在第一次创建后就会保存在缓存中,下次页面切换时直接从缓存中读取。
     
        场景:页面打开后,基本涉及到数据更改的组件用<keep-alive>包裹,<keep-alive>和<template>一样,不会显示在页面上。
     
        生命周期:加上keep-alive后产生的两个生命周期:activated、deactivated
            created() {
                console.log("歌手创建")
            },
            mounted() {
                console.log("歌手挂载")
            },
            activated() {
                console.log("歌手缓存激活,进入keep-alive")
            },
            deactivated() {
                console.log("歌手缓存停用,离开keep-alive")
            },
            第一次进入歌手页面,会触发创建、挂载、缓存激活,离开时触发缓存停用,后面再进入和离开只会触发缓存激活和缓存停用。这样用keep-alive包裹的组件不进行数据请求了,以此来减少http请求,如果需要数据请求,在activated生命周期进行数据请求。
     
        属性:<keep-alive include="" exclude="" max=5></keep-alive>
            include:包括,这里填写的组件是将被缓存的组件,属性值为字符串或正则
            exclude:排除,这里填写的组件是不需要被缓存的组件(实时更新的组件),属性值为字符串或正则
            max:最多能缓存多少个组件,属性值为Number
     
            注意:
                1、include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
                    <!-- 逗号分隔字符串 -->
                    <keep-alive include="a,b">
                        <component :is="view"></component>
                    </keep-alive>
    
                    <!-- 正则表达式 (使用 `v-bind`) -->
                    <keep-alive :include="/a|b/">
                        <component :is="view"></component>
                    </keep-alive>
    
                    <!-- 数组 (使用 `v-bind`) -->
                    <keep-alive :include="['a', 'b']">
                        <component :is="view"></component>
                    </keep-alive>
                2、include和exclude不能同时使用
     
        例子:App.vue中给router-view套上keep-alive标签:
            <keep-alive>
                <router-view></router-view>
            </keep-alive>
        此时,在推荐和歌手组件来回切换的时候,在Network里的js,就会进行缓存,不会一直请求。

    ### 数据本地化:localStorage的二次封装

        思路:
            (1)考虑兼容问题
            (2)简化读取与存储
            (3)有时间限制
        
        代码实现:
            ①在utils中新建localStorage.js文件:
                export default{
                    set(key,data,expiresTime){
                        let obj={
                            data:data,
                            ctime:(new Date()).getTime(),//时间戳,同Date.now()
                            expiresTime:expiresTime||1000*60*60 // 如果没有传过期时间,则设置过期时间一个小时
                        }
                        localStorage.setItem(key,JSON.stringify(obj));
                    },
                    get(key){
                        let obj=JSON.parse(localStorage.getItem(key));
                        let getItem=(new Date()).getTime();
                        if(getItem-obj.ctime>=obj.expiresTime){
                            // 如果超时
                            localStorage.removeItem(key);
                            return null;
                        }else{
                            // 未超时
                            return obj.data;
                        }
                    }
                }
            ②main.js中引入并注册到Vue对象中:
                import LocalStorage from "utils/localStorage.js";
                Vue.prototype.$localStorage=LocalStorage;
            ③在任意组件,如Singer.vue中,通过this.$localStorage对象可以使用set()和get():
                this.$localStorage.set("name","吴小明")
                console.log(this.$localStorage.get("name"))

    ### 图片懒加载插件:vue-lazyload(Singer.vue)

        ①下载依赖:
            npm install vue-lazyload
        ②引入和添加配置项(main.js):
            import VueLazyLoad from "vue-lazyload";
            Vue.use(VueLazyLoad,{
                preLoad:1.3,                               // 预加载
                error:require("./assets/musicLogo.png"),   // 错误时显示
                loading:require("./assets/musicLogo.png"), // 加载时显示
                attempt:1                                  // 每次加载多少张
            });
        ③v-lazy指令(Singer.vue):
            将需要图片懒加载的img中 :src 替换为 v-lazy:
                <img :src="info.avatar">
                替换为
                <img v-lazy="info.avatar">
                此时,在Singer.vue中Network的img只加载了首屏的图片,随着屏幕滚动,加载更多的图片。

    ### UI框架 

        pc端:iView框架:https://www.iviewui.com/
        移动端:mint-ui

    ### mint-ui(Rank.vue)

        ①下载依赖:
            npm install mint-ui
        ②main.js中做全局引入,任何组件都可以用:
            import MintUI from "mint-ui";
            import "mint-ui/lib/style.css";
            Vue.use(MintUI);
        ③Rank.vue中引入想要使用的组件(Toast提示和loading条):
            import {Toast,Indicator} from "mint-ui";
        ④设置Toast提示的按钮和点击事件:
            <button @click="toast">toast</button>
    
    
            methods: {
                toast(){
                    Toast({
                        message:"点击我了,操作成功",   // 信息
                        position:"center",  // 位置
                        duration:3000       // 持续时间
                    });
                }
            }
        ⑤模拟数据加载时的loading条:
            created() {
                Indicator.open({
                    text:"加载中",
                    spinnerType:"fading-circle"
                });
                setTimeout(() => {
                    Indicator.close();
                }, 2000);
            }
        ⑥在main.js中已经引入mint-ui和css文件的前提下,可以直接在组件中使用mt-button组件(Toast()需要在使用的时候在组件中进行引入):
            <mt-button type="default">default</mt-button>
            <mt-button type="primary">primary</mt-button>
            <mt-button type="danger">danger</mt-button>

    ### 封装加载loading条(Recommend.vue)

        ①创建Loading组件:
            <template>
                <div class="loading">
                    <img :src="img">
                </div>
            </template>
            <script>
            // 以base64的方式引入图片
            import img from "../assets/loading.gif";
            export default {
                data() {
                    return {
                        img:img
                    }
                },
            }
            </script>
            <style lang="less">
            @import "~style/index.less";
            .loading{
                position: fixed;
                top: 0;bottom: 0;
                left: 0;right: 0;
                margin: auto;
                display: flex;
                justify-content: center;
                align-items: center;
                img{
                    .w(30);
                    .h(30);
                }
            }
            </style>
        ②Recommend.vue中引入组件,并且在data中声明 loading:true
            import Loading from "components/Loading.vue";
    
            data() {
                return {
                    loading:true,
                    songList:[]
                }
            }
        ③对ul中数据进行loading条优化,Loading组件和ul是二选一的关系:
            <Loading v-if="loading"></Loading>
            <ul v-else class="songList">
                    <!-- -->
                <li v-for="(item,index) in songList" :key="index" @click="goDateil(item.creator.encrypt_uin)">
                    <img :src="item.imgurl">
                    <div class="info">
                        <h2>{{item.creator.name}}</h2>
                        <p>{{item.dissname}}</p>
                    </div>
                </li>
            </ul>
        ④在拿到songList数据的同时,设置 this.loading=false;
            axios.get(url,(err,data)=>{
            }).then((data)=>{
                this.songList=data.data.list;
                this.loading=false;
            });

    ### axios请求以post方式请求 x-www 格式的数据(demo)

        原理:axios请求格式默认为json,有的时候需要请求 x-www-form-urlencoded 的格式,此时页面会报404,需要将 content-type 属性设置为 application/x-www-form-urlencoded ,再将data参数用qs.stringify()进行转化。
     
        ①下载axios和qs依赖:
            npm install axios qs
        ②main.js中引入axios,并设置给Vue:
            import axios from "./utils/axios.js";
            Vue.prototype.$axios=axios;
        ③根目录下新建vue.config.js文件处理跨域:
            module.exports={
                devServer:{
                    port:8989,
                    proxy:{
                        "/maoEr":{
                            target:"https://www.missevan.com",// 目标服务器路径
                            changeOrigin:true,// 是否允许改变源,默认为true
                            pathRewrite:{// 重写路径
                                "^/maoEr":""
                            }
                        },
                    }
                }
            }
        ④App.vue中做数据请求(引入qs:import qs from "qs";):
            mounted() {
                let url="/maoEr/site/getcomment";
                let data={
                    order:1,
                    pagesize:10,
                    type:1,
                    eId:1284079,
                    p:1
                }
                const options={
                    method:"POST",
                    headers:{"content-type":"application/x-www-form-urlencoded"},
                    data:qs.stringify(data),// 需要下载qs依赖,npm i qs,node中queryString()有同样效果
                    url:url,
                }
                this.$axios(options).then((data)=>{
                    console.log(data)
                });
            }
        注意:如果使用node中的queryString有一样的效果,可以不用下载qs依赖。
            ①先引入queryString:
                const querystring = require('querystring');
            ②
             data:qs.stringify(data),    
                 替换为
              data:querystring.stringify(data),

    ### nginx代理(demo)

        线上环境:npm run build 打包成一个静态文件夹,丢到服务器目录下,上线完成。
     
        场景:解决npm run build之后的代理失效
     
        原理:在vue.config.js中配置的代理服务器是由本地的npm run serve启动的服务器做支持,而npm run build后的index.html没有服务器支持,代理失效,数据请求全部失效。
     
        注意:npm run build后的index.html直接打开会报错,此时将其中所有的css和js文件前面加上 . ,表示当前路径下。
     
        步骤:
            ①下载nginx:http://nginx.org/en/download.html
            ②将dist文件夹拷贝到nginx/html文件夹中
            ③双击nginx.exe,cmd打开nginx目录,输入nginx -s reload,没有报错就成功了
            ④在地址栏输入当前电脑的ip,可以进入welcome to nginx,相当于双击打开index.html,在地址后面加上 /dist 可以打开 npm run build 后的项目。此时打开Network,可以发现请求地址由 http://localhost:52330/maoEr/site/getcomment 变为 http://192.168.43.185/maoEr/site/getcomment
            ⑤nginx/conf/nginx.conf文件下设置跨域代理:
                location /maoEr {
                    proxy_pass https://www.missevan.com/;#注意这个域名后面有 / ,如果是ip不用加 /
                }
            ⑥远程服务器上双击nginx.exe,nginx文件夹进入cmd,输入nginx -s reload
        nginx命令:
            nginx -s reload
            start nginx
            nginx -s stop

    ### 前端拦截 前端安全

        1、鉴权 token session+cookie
        2、拦截 路由拦截器 路由守卫 路由导航

    ### 路由守卫

        1、全局前置守卫(所有的路由跳转都会经过这个函数):(router/index.js)
            router.beforeEach((to,from,next)=>{
                console.log("去哪里",to)
                console.log("从哪来",from)
                let token=false;
                if(to.name=="About"){
                    if(token){
                        next();
                    }else{
                        next("/login");
                    }
                }else{
                    next();
                }
            })
            场景:控制某些页面未登录情况下不可进,跳转至登录页面。
     
        2、路由独享守卫(路由配置项中使用,只对当前路由起作用):(router/index.js)
            {
                path: '/login',
                name: 'Login',
                component: () => import('../views/Login.vue'),
                beforeEnter: (to, from, next) => {
                    console.log("去哪儿",to)
                    console.log("从哪来",from)
                    next();
                }
            }
        3、组件内守卫:(About.vue)
            (1)进入路由前(此时路由还没有进来,组件未创建,没有this):
                beforeRouteEnter(to, from, next) {
                    console.log("组件进入前")
                    next();
                }
            (2)路由更新时:
     
                组件复用时,例如用动态导航传参(在路由中更改about的path为 /about/:id,通过params接收参数),在mounted生命周期中只有第一次能获取到参数,这会造成在详情页的地址栏更换,但页面不变。此时,可以用到beforeRouterUpdate(),可以用to.params.id获取到参数。
                beforeRouterUpdate(to, from, next) {
                    console.log("组件更新",to.params.id)
                    next();
                }
                另外,可以通过watch监听获取参数:
                    watch: {
                        $route(newValue){
                            console.log("watch",newValue.params.id)
                        }
                    }
            (3)路由离开时,可以在离开前做一些判断:
                beforeRouteLeave(to, from, next) {
                    console.log("组件要离开",this)
                    // console.log("去哪儿", to);
                    // console.log("从哪来", from);
                    let state = confirm("确定要离开吗");
                    if (state) {
                        next();
                    }
                }

    ### mint-ui下拉刷新,上拉加载更多

        ①下载依赖:
            npm install mint-ui
        ②main.js中做全局引入:
            import MintUI from "mint-ui"
            import "mint-ui/lib/style.css"
            Vue.use(MintUI)
        ③Home.vue中:
            <template>
                <div class="home">
                    这里是首页
                    <mt-loadmore
                        :top-method="loadTop"
                        :bottom-method="loadBottom"
                        :bottom-all-loaded="allLoaded"
                        ref="loadmore"
                    >
                        <ul>
                            <li v-for="(item,index) in list" :key="index">{{item.name}}</li>
                        </ul>
                    </mt-loadmore>
                </div>
            </template>
            <script>
            export default {
                data() {
                    return {
                        list: [
                            { name: "AAA" },
                            { name: "BBB" },
                            { name: "CCC" },
                            { name: "DDD" },
                            { name: "EEE" },
                            { name: "FFF" },
                            { name: "RRR" },
                            { name: "HHH" },
                            { name: "NNN" }
                        ],
                        allLoaded: false
                    };
                },
                methods: {
                    loadTop() {
                        let url = "/api/city/city/getHotCityList?version=6.0.4&referer=2";
                        this.$axios
                            .get(url, () => {})
                            .then(data => {
                                this.list = data.data.hot_city_List; // 拿到数据后让页面回到原位
                                this.$refs.loadmore.onTopLoaded();
                            });
                    },
                    loadBottom() {
                        setTimeout(() => {
                            this.list = this.list.concat([
                                { name: "窗前明月光" },
                                { name: "疑是地上霜" },
                                { name: "举头望明月" },
                                { name: "低头思故乡" }
                            ]);
                            console.log(this.list);
                            this.allLoaded = false;
                            this.$refs.loadmore.onBottomLoaded();
                        }, 1000);
                    }
                }
            };
            </script>
            <style>
            .home {
                overflow: scroll;    // 注意:如果上拉函数无法触发,是因为这里没有设置超出滚动
            }
            li  {
                height: 50px;
                font-size: 20px;
            }
            .mint-loadmore-text  {
                font-size: 20px !important;
            }
            .mint-loadmore-content {
                font-size: 20px !important;
            }
            </style>

    ### Q:

        1、自己封装过哪些组件和模块?
            组件:loading条的封装
            模块:localStorage的二次封装
  • 相关阅读:
    [LeetCode][JavaScript]Copy List with Random Pointer
    [LeetCode][JavaScript]Best Time to Buy and Sell Stock II
    [LeetCode][JavaScript]Best Time to Buy and Sell Stock
    [LeetCode][JavaScript]Populating Next Right Pointers in Each Node
    [LeetCode][JavaScript]Text Justification
    [LeetCode][JavaScript]LRU Cache
    用CRTP在C++中实现静态函数的多态
    C++的静态分发(CRTP)和动态分发(虚函数多态)的比较
    用Y分钟学会X
    看看你能认出多少种编程语言
  • 原文地址:https://www.cnblogs.com/wuqilang/p/12310518.html
Copyright © 2011-2022 走看看