全局注册组件
- 方法一
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: {}
}
}
路由守卫
- 路由前置守卫
// 导入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开发
配置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(版本号)