各种功能实现总结

156 阅读1分钟

全局注册组件

- 方法一

    components.js文件:
      1. Vue.use(params)方法中可以 params 传递函数或对象作为参数
      2. params 一般是对象 对象中有一个方法  名称叫install
      3.Vue.use(obj) install方法会自动执行
      4. install方法中有形参是Vue
      import PageTools from './PageTools/index'
      import UploadExcel from './UploadExcel/index'
      import ImageUpload from './imageUpload/index'

      export default {
        install(Vue) {
          Vue.component('PageTools', PageTools)
          Vue.component('UploadExcel', UploadExcel)
          Vue.component('ImageUpload', ImageUpload)
        }
       }

    main.js:
       // 导入全局组件
       import components from '@/components'
       Vue.use(components)

- 方法二

components.js文件:
  1. 使用的是webpack require.context('./', true, /.vue$/)方法
  2. 参数1:路径【表示公共的组件的目录】,
     参数2:文件深入循环查找【bool】,这个参数是false值会找第一级文件,不会找文件夹
     参数3:正则【最终要使用的组件】 
  *注意:这种方法注册全局组件,需要用到组件名-name,必须写
  
  const requireComponent = require.context('./libary', true, /\.vue$/)
    export default {
      install (Vue) {
        requireComponent.keys().forEach((item) => {
          Vue.component(
            requireComponent(item).default.name,
            requireComponent(item).default
          )
        })
      }
    }

  main.js:
     // 导入全局组件文件
     import components from '@/components'
     Vue.use(components)

全局注册指令

- 方法一

    directives.js文件:
      export const imageerr = {
      inserted(el, binding) {
        el.onerror = function() {
          el.src = binding.value
        }
      }
    }
    
    export const color = {
      inserted(el, binding) {
        el.style.color = binding.value
      }
    }

     main.js:
         // 导入自定义指令文件
         import * as directives from '@/directives'
         // 自定义模块-directive
         Object.keys(directives).forEach(item => Vue.directive(item, directives[item]))

- 方法二

    //导入vue
     import Vue from 'vue'
    // 自定义指令
    // Vue.directive('自定义指令名称',配置对象)
    Vue.directive('imageerr', {
      inserted(el, binding) {
        el.onerror = () => {
          el.srs = binding.value
        }
      }
    })
    
    Vue.directive('color', {
      inserted(el, binding) {
        el.style.color = binding.value
      }
    })
    
     main.js:
         // 导入全局指令文件
         import { imageerr, color } from '@/directives'
         // 自定义模块-directive
         Vue.directive(imageerr, color)

全局注册过滤器

- 方法一

    filters.js文件:
         // 导入时间插件
         import dayjs from 'dayjs'
        export const formatDate = function(value, str = 'YYYY年MM月DD日') {
          return dayjs(value).format(str)
        }

    main.js:
         // 导入过滤器文件
         import * as formatDate from '@/Filters'
         // 过滤器-filter
         Object.keys(formatDate).forEach(item => Vue.filter(item, formatDate[item]))

   使用: formatDate('YYYY-MM-DD')//想要什么模式调用时输入

跨域的几种解决方案

- 方法一:jsonp 【前端后端实现】

jsonp: 利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。
JSONP请求一定需要对方的服务器做支持才可以。

JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。
缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。

声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为
要获取目标数据(服务器返回的data)。

创建一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址
中向服务器传递该函数名(可以通过问号传参:?callback=show)。

服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,
例如:传递进去的函数名是show,它准备好的数据是show('我不爱你')。

最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。

- 方法二:# CORS 【后端实现】

CORS:跨域资源共享(CORS)是一种机制;当一个资源访问到另外一个资源(这个资源放在不同的域名或者
不同的协议或者端口),资源就会发起一个跨域的HTTP请求需要浏览器和服务器同时支持;

1.  整个CORS通信,都是浏览器自动完成。浏览器发现了AJAX请求跨源,就会自动添加一些附加的头信息,
    有时还会多出一次附加的请求,但用户不会有感觉;
2.  实现CORS的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
3.  服务器对于不同的请求,处理方式不一样; 有简单请求和非简单请求

- 方法三:# 配置反向代理

配置反向代理
    proxy: {
      // 当地址中有/api的时候会触发代理机制
      '/api': {
        target: 'http://ihrm-java.itheima.net/', // 要代理的服务器地址  这里不用写 api
        changeOrigin: true // 是否跨域
        // 重写路径
        // pathRewrite: {}
      }
    }

image.png

路由守卫

- 路由前置守卫

    // 导入router
        import router from '@/router'
    // 导入store
        import store from '@/store'
    import NProgress from 'nprogress' // 引入一份进度条插件
    import 'nprogress/nprogress.css' // 引入进度条样式
    *注意*
        // to:要去那个组件
        // from:从哪个组件来
        // next:next()放行  next(false)不放行  next(路劲)
        // NProgress.done() 当有路径跳转的时候,不会进后置守卫,需要手动关闭    
        
   // 前置守卫
router.beforeEach(async(to, from, next) => {
  NProgress.start()  //进度条插件开
  const token = store.getters.token
  //判断是否有token
  if (token) {
    // 有token
    // 是否要去登录页
    if (to.path === '/login') {
      next('/')
      NProgress.done()  //进度条插件关
    } else {
      // 跳转之前获取用户信息
      if (!store.state.user.userInfo.userId) {
        const { roles: { menus }} = await store.dispatch('user/getUserInfo')
        const otherRoutes = await store.dispatch('permission/filterRoutes', menus)
        // 404 page must be placed at the end !!!(404路由一定要在最后面)
        
        //动态添加路由
        router.addRoutes([...otherRoutes, { path: '*', redirect: '/404', hidden: true }])
        next({
          ...to,
          replace: true // 重进一次,不保留重复历史
        })
      }
      next()
    }
  } else {
    // 无token
    // 是否要去白名单
    if (weiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
      NProgress.done()  //进度条插件关
    }
  }
})

- 路由后置守卫

    // 导入router
        import router from '@/router'
    // 导入store
        import store from '@/store'
        import NProgress from 'nprogress' // 引入一份进度条插件
        import 'nprogress/nprogress.css' // 引入进度条样式
        
    *注意*
        // to:要去那个组件
        // from:从哪个组件来
        // next:next()放行  next(false)不放行  next(路劲)
        // NProgress.done() 当有路径跳转的时候,不会进后置守卫,需要手动关闭    
        
    // 后置守卫
    router.afterEach((to, from) => {
      NProgress.done() //进度条插件关
    })

vue中如何使用ESlint开发

、vue中如何使用ESlint开发

配置vscode=》setting.json

{
  "workbench.colorTheme": "Default Dark+",
  "editor.fontSize": 14,
  "workbench.editor.enablePreview": true, //预览模式关闭
  "editor.formatOnSave": true, // #每次保存的时候自动格式化
  // 自动修复
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.enable": true, //是否开启vscode的eslint
  // 配置 ESLint 检查的文件类型
  "eslint.validate": ["javascript", "vue", "html"],
  "eslint.options": {
    //指定vscode的eslint所处理的文件的后缀
    "extensions": [".js", ".vue", ".ts", ".tsx"]
  },
  "files.associations": {
    "*.wpy": "vue",
    "*.wxml": "wxml",
    "*.cjson": "jsonc",
    "*.wxss": "css",
    "*.wxs": "javascript",
    "*.html": "html"
  },
  "emmet.includeLanguages": {
    "wxml": "html"
  },
  "minapp-vscode.disableAutoConfig": true,
  // vscode默认启用了根据文件类型自动设置tabsize的选项
  "editor.detectIndentation": false,
  // 重新设定tabsize
  "editor.tabSize": 2,
  //  #去掉代码结尾的分号
  "prettier.semi": false,
  //  #使用单引号替代双引号
  "prettier.singleQuote": true,
  //  #让函数(名)和后面的括号之间加个空格
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  // #让vue中的js按编辑器自带的ts格式进行格式化
  "vetur.format.defaultFormatter.js": "prettier-eslint",
  "git.enableSmartCommit": true,
  "editor.quickSuggestions": {
    "strings": true
  },
  //一定要在vutur.defaultFormatterOptions参数中设置,单独修改prettier扩展的设置是无法解决这个问题的,因为perttier默认忽略了vue文件(事实上从忽略列表移除vue也不能解决这个问题)
  "vetur.format.defaultFormatterOptions": {
    "prettier": {
      "semi": false, // 格式化不加分号
      "singleQuote": true // 格式化以单引号为主
    },
    "js-beautify-html": {
      // force-aligned | force-expand-multiline
      "wrap_attributes": "force-aligned"
    },
    "prettyhtml": {
      "printWidth": 100,
      "singleQuote": false,
      "wrapAttributes": false,
      "sortAttributes": true
    }
  },
  // 插件KoroFileHeader
  // 文件头部注释-快捷键crtl+alt+i(window),ctrl+cmd+t (mac)
  "fileheader.customMade": {
    "Descripttion": "",
    //"version": "",
    "Author": "voanit",
    "Date": "Do not edit",
    "LastEditors": "voanit",
    "LastEditTime": "Do not Edit"
  },
  //函数注释-快捷键ctrl+alt+t (window), ctrl+alt+t(mac)
  "fileheader.cursorMode": {
    "name": "",
    // "test": "test font",
    // "msg": "",
    "param": "",
    "return": ""
  },
  //安装live Server插件
  "liveServer.settings.donotVerifyTags": true,
  "liveServer.settings.donotShowInfoMsg": true,
  "liveServer.settings.NoBrowser": true,
  "liveServer.settings.CustomBrowser": "chrome", //设置默认打开的浏览器
  "liveServer.settings.host": "127.0.0.1",
  "liveServer.settings.port": 5000, //设置本地服务的端口号
  "liveServer.settings.root": "/distserver",
  "[vue]": {
    "editor.defaultFormatter": "octref.vetur"
  },
  "javascript.updateImportsOnFileMove.enabled": "never",
  "javascript.implicitProjectConfig.experimentalDecorators": true,
  "workbench.editor.showTabs": true,
  "terminal.integrated.rendererType": "dom",
  "sync.gist": "396472a5bb443e3680d5a0e2ffccefe8",
  "diffEditor.ignoreTrimWhitespace": true,
  "launch": {},
  "[jsonc]": {
    "editor.defaultFormatter": "remimarsal.prettier-now"
  },
  "[typescript]": {
    "editor.defaultFormatter": "remimarsal.prettier-now"
  },
  "json.schemas": [
    {
      "fileMatch": ["/myfile"],
      "url": "schemaURL"
    }
  ],
  "window.zoomLevel": 1,
  "files.autoSave": "afterDelay",
  "tabnine.experimentalAutoImports": true
}

性能优化汇总

1.减少重绘  重排,回流
重绘:当样式发生改变时,浏览器就会重现渲染页面
重排,回流:当dom结构发生改变时,浏览器就会重现渲染页面
2.减少ajax请求
3.cdn加速



路由懒加载

    import Layout from '@/layout'
    export default {
      path: '/approvals',
      component: Layout,
      children: [{
        path: '',
        name: 'approvals',
        component: () => import('@/views/approvals'),
        meta: { title: '审批', icon: 'tree-table' }
      }]
    }
    
  {
    path: '/',
    name: 'layout',
    // 魔法注释:打包之后文件名上有layout
    component: () => import(/* webpackChunkName: "layout" */'@/views/layout'),
    children: [
      {
        path: '',
        name: 'home',
        component: () => import(/* webpackChunkName: "layout" */'@/views/home')
      }
    ]
  }

数据懒加载

    import { ref } from 'vue'
    import { useIntersectionObserver } from '@vueuse/core'

    export const useLazyData = (fn) => {
      const target = ref(null)
      const { stop } = useIntersectionObserver(
        target,
        ([{ isIntersecting }], observerElement) => {
          // 在此处可根据isIntersecting来判断,然后做业务
          if (isIntersecting) {
            stop()
            if (!fn) return
            fn()
          }
        }
      )
      return target
    }

图片懒加载

//导入默认图片(图片加载不出来时)
import defaultImg from '@/assets/images/200.png'
export default {
  install (Vue) {
    Vue.directive('lazy', {
      mounted (el, binding) {
        const observer = new IntersectionObserver(([{ isIntersecting }]) => {
          if (isIntersecting) {
            el.onerror = function () {
              el.src = defaultImg
            }
            el.src = binding.value
            observer.unobserve(el)
          }
        }, { threshold: 0.01 })
        // 监听
        observer.observe(el)
      }
    })
  }
}

防抖 节流

<body>
  <input type="text" class="add">
  <script>
    let fang = document.querySelector('.add')
    let time = null
    fang.oninput = function (e) {
      clearTimeout(time)  //防抖第二次执行事件时清空上一次的定时器
      time = setTimeout(() => {
        console.log(this);
        console.log(e.data)
      }, 1000)
    }
    
    
    window.onmousemove = function (e) {
      if (!time) {  //节流,0.5秒后赋值null后为true,在执行
        console.log(e.clientX, e.clientY);
        time = setTimeout(() => {
          time = null
        }, 500)
      }
    }
  </script>

插槽

面包屑

插槽:自定义内容
子组件1:
     <div class="xtx-bread">
        <slot></slot>
     </div>
     
子组件2:
     <div class="xtx-bread-item">
        <router-link v-if="to" :to="to">
          <slot></slot>
        </router-link>
        <template v-else>
          <slot></slot>
        </template>
        <span>{{ separator }}</span>
     </div>
     
 父组件:
  <!-- 面包屑 -->
  <XtxBread>
    <XtxBreadItem to="/">首页</XtxBreadItem>
    <XtxBreadItem :to="`/category/${goods.categories[1].id}`">
      {{ goods.categories[1].name }}
    </XtxBreadItem>
    <XtxBreadItem :to="`/category/sub/${goods.categories[0].id}`">
      {{ goods.categories[0].name }}
    </XtxBreadItem>
    <XtxBreadItem>
      {{ goods.name }}
    </XtxBreadItem>
  </XtxBread>

git指定版本

第一步:初始化
    git init
第二步:git他的项目地址
    git remote add origin 地址
第三步:把他的文件全部pull下来
    git pull origin master
第四步:pull指定的版本号(他的提交记录)
    git checkout ID(版本号)