记录Vue开发过程碰到的一些问题记录
程序员文章站
2022-04-24 14:25:37
...
组件
组件样式
scoped会把样式限制在组件内,不能影响其他组件或子组件,要想影响子组件可以使用深度选择器>>>,例如:.m-con >>> .u-center
解决前后端分离开发阶段测试跨域问题
proxyTable: {
// 用于开发,解决前后端分离开发的跨域问题
'/api': {
target: 'http://127.0.0.1:8000/',
changeOrigin: true
},
}
// 跨域解决后还有个问题就是后端重定向,需要将重定向的地址也代理到相应的地址上,配置如下:
onProxyRes: function(proxyRes, req, res) { // 监听代理的返回结果
const location = proxyRes.headers['location']
const locationRE = /http(?:s)?:\/\/[0-9.:]+?(\/.*?[a-zA-Z]+)$/
if(location) { // 解决前后端分离,后端重定向问题
const matched = location.match(locationRE)
const matchGroup = matched && matched[1]
proxyRes.headers['location'] = matchGroup ? `http://xx.xx.xx.xx:8081${matchGroup}` : location
}
}
动画组件
// 几个注意的点,容易被坑
// 各个过渡阶段的类名会添加到根节点上,即transition组件中的根节点
// 类名中如果嵌套使用选择器在过渡类名下需要加入过渡时间,动画也是如此,否则过渡或动画会一闪而过
.match-slider-enter-active{
transition: all 5s;
.g-top{
.m-top {
animation: leftSlider 5s;
}
.m-bottom{
animation: rightSlider 5s;
}
}
}
采坑
配置网站facvicon.ico,图片要放在项目的根目录下,然后在build目录下的webpack.dev.conf.js和webpack.prod.conf.js的new HtmlWebpackPlugin中配置
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
favicon: path.resolve('favicon.png')
})
解决IE上placeholder的兼容性问题,使用到vue的mixins
// 定义mixin
import {isIE, supportPlaceholder} from 'common/js/env.js'
export const fixPlaceholder = {
methods: {
_fixPlaceholder() {
if(isIE && !supportPlaceholder) {
const inputs = document.querySelectorAll('input')
for(let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const placeholder = input.getAttribute('placeholder')
if (input.type === 'password') {
input.setAttribute('data-passwd', true)
input.type = 'text'
input.value = placeholder
} else {
input.value = placeholder
}
input.onfocus = function (e) {
if(e.target.value === placeholder) {
e.target.value = ''
}
}
input.onblur = function (e) {
if(e.target.value.trim() === '') {
e.target.value = placeholder
}
}
}
}
}
}
}
Axios采坑
// post请求默认把请求对象转成json,不管是否设置了Content-Type': 'application/x-www-form-urlencoded,如果要传入表单类型的数据就需要使用qs
import qs from 'qs'
export function login(userName, passWord, validateCode) {
return netWork.post(apis.common.login, qs.stringify({
userName: userName,
passWord: hex_md5(passWord),
validateCode: validateCode.toUpperCase()
})).then((res) => {
return Promise.resolve(res.data)
})
}
Element-ui采坑
table组件表头和内容错误,使用如下样式代码解决
@aaa: ~'>>>';
.wrap {
@{aaa} .component1 {
width: 120px;
}
/deep/ .component2 {
width: 130px;
}
}
table组件列宽度设置百分比使用min-width属性
设置表头颜色,在el-table上设置:header-cell-style="{background: ‘#f2f2f2’, color: ‘#666’}"
vuecli3
去掉代码混淆config.optimization.minimize(false)
打包时去掉console
configureWebpack: (config)=>{
if(process.env.NODE_ENV === 'production'){
// 返回一个将会被合并的对象
return {
optimization:{
minimizer: [
new TerserPlugin({
sourceMap:false,
terserOptions:{
compress:{
drop_console : true
}
}
})
]
}
}
}
}
分析工具:webpack-bundle-analyzer,需要做如下配置,然后npm run build --report
chainWebpack (config) {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置
config.optimization.minimizer('terser').tap((args) => {
args[0].terserOptions.compress.drop_console = true // 打包时去掉console输出
return args
})
// 打包分析工具
config.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer).BundleAnalyzerPlugin).end()
}
}
插槽
基本使用
// 父级:
<template v-slot:header="scope">
{{scope.xxx}}
</template>
// 父级(Render):
h('SlotChildRender', {
props: {
columns: ['name', 'age'],
},
scopedSlots: {
default(props) {
return h('div', `slot child render ${props.message}`)
},
name(props) {
return h('div', `name: ${props.name}`)
},
age(props) {
return h('div', `age:${props.age}`)
}
}
})
// 子级(template写法):
<slot name="header" :name1="name1"></slot>
// 子级(Render写法):
return h('div', [
this.$scopedSlots.default({
message: this.message,
name: this.name,
age: this.age
}),
...this.columns.map(item => {
console.log('item');
console.log(item);
return this.$scopedSlots[item]({
name: this.name,
age: this.age
})
})
])
静态插槽使用this. s l o t s , 动 态 插 槽 使 用 t h i s . slots,动态插槽使用this. slots,动态插槽使用this.scopedSlots
// 静态插槽:
render: function (createElement) {
// `<div><slot></slot></div>`
return createElement('div', this.$slots.default)
}
// 动态插槽:
props: ['message'],
render: function (createElement) {
// `<div><slot :text="message"></slot></div>`
return createElement('div', [
this.$scopedSlots.default({
text: this.message
})
])
}
如果要用渲染函数向子组件中传递作用域插槽,可以利用 VNode 数据对象中的 scopedSlots 字段:
render: function (createElement) {
// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
return createElement('div', [
createElement('child', {
// 在数据对象中传递 `scopedSlots`
// 格式为 { name: props => VNode | Array<VNode> }
scopedSlots: {
default: function (props) {
return createElement('span', props.text)
}
}
})
])
}
Render渲染组件
事件 & 按键修饰符
对于 .passive、.capture 和 .once 这些事件修饰符,Vue 提供了相应的前缀可以用于 on:
修饰符 前缀
.passive &
.capture !
.once ~
.capture.once 或
.once.capture ~!
例如:
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}
对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:
修饰符 处理函数中的等价操作
.stop event.stopPropagation()
.prevent event.preventDefault()
.self if (event.target !== event.currentTarget) return
按键:.enter, .13 if (event.keyCode !== 13) return
(对于别的按键修饰符来说,可将 13 改为另一个按键码)
修饰键:.ctrl, .alt, .shift, .meta if (!event.ctrlKey) return
(将 ctrlKey 分别修改为 altKey、shiftKey 或者 metaKey)
这里是一个使用所有修饰符的例子:
on: {
keyup: function (event) {
// 如果触发事件的元素不是事件绑定的元素
// 则返回
if (event.target !== event.currentTarget) return
// 如果按下去的不是 enter 键或者
// 没有同时按下 shift 键
// 则返回
if (!event.shiftKey || event.keyCode !== 13) return
// 阻止 事件冒泡
event.stopPropagation()
// 阻止该元素默认的 keyup 事件
event.preventDefault()
// ...
}
}
插件
通过全局方法 Vue.use()
使用插件。它需要在你调用 new Vue()
启动应用之前完成:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
// 也可以传入一个可选的选项对象:
Vue.use(MyPlugin, { someOption: true })
开发插件:
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
Vue底层原理
Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些property 全部转为 getter/setter
vuex插件
Vuex 的 store 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数: