Vue2.x 项目踩坑笔记
设置路径别名、全局引入scss文件
给文件设置路径别名,方便在组件内引入文件,不必写太长的路径名称。
全局引入scss文件,不必在单个组件内再次引入,可以直接使用。例如:全局变量、px2rem函数等文件
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
css: {
loaderOptions: {
// 给 sass-loader 传递选项
// 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
// 因为 `scss` 语法在内部也是由 sass-loader 处理的
// 但是在配置 `data` 选项的时候
// `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
// 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
scss: {
additionalData: `
@import "assets/styles/common/variables.scss";
@import "assets/styles/common/px2rem.scss";
@import "assets/styles/iconfont/iconfont.scss";
`
},
}
},
chainWebpack: config => {
config
.resolve.alias
.set('@', resolve('src')) //配置src目录别名
.set('assets', resolve('src/assets')) //配置src/assets目录别名
.set('components', resolve('src/components')); //配置src/components目录别名
}
}
动态路由加载
为了解决项目进入时候白屏bug
const router = new VueRouter({
routes: [
{
path: '/',
name: 'index',
component: () => import("@/views/Index.vue")
}
]
});
prop 命名方案(驼峰式和串联式)
HTML 属性名称对大小写不敏感,因此浏览器会将所有大写字符解释为小写字符。也就是说。当你在你 DOM 模板中书写 prop 时,你应当将驼峰式(camelCase)转写为等价的(连字符分割的)串联式(kebab-case):
Vue.component('blog-post', {
// 在 JavaScript 中使用驼峰式(camelCase)
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中使用串联式(kebab-case) -->
<!-- 向 props传递一个静态值 -->
<blog-post post-title="hello!"></blog-post>
还可以通过 v-bind 给 props 分配动态值,就像这样:
<!-- 动态分配一个变量对应的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态分配一个复合表达式对应的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
再次申明,如果是在使用字符串模板的场景,则没有这些限制。
路由跳转拼接参数
<router-link :to="`/topic/${item.id}`" :title="item.id">
</router-link>
beforeRouteEnter不能通过this访问组件实例,但是可以通过 vm 访问组件实例
// 进入路由
beforeRouteEnter(to, from, next) {
// beforeRouteEnter不能通过this访问组件实例,但是可以通过 vm 访问组件实例
next((vm) => {
console.log('beforeRouteEnter',this);
// 先解绑,防止多次执行
vm.eventBus.$off('aaa');
});
},
滚动到页面底部加载数据
在生命周期mounted中进行监听滚动:
mounted () {
window.addEventListener('scroll', this.scrollToTop)
},
在方法中定义监听滚动执行的方法:
scrollToTop() {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
console.log(scrollTop)
},
记得在离开当前路由解绑scroll
事件
beforeRouteLeave(to, form, next){
window.removeEventListener('scroll',this.scrollToTop);
next();
}
渲染异步数据,浏览器报错
<img class="avatar" v-if="item.author" :src="item.author.avatar_url" />
如果异步请求的数据出现报错,可以通过v-if
判断一下,注意不能使用v-show
,v-show的机制是加载后,根据条件判断是否显示,当然渲染组件的时候也可以这样做
菜单切换获取对应参数并触发请求数据
参数或查询的改变并不会触发进入/离开的导航守卫,但是可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
父组件修改子组件变量
有时候父组件触发的实际需要修改子组件内的data数据,这时候请给子组件绑定ref
属性,在父组件触发时间内修改子组件的变量
<template>
<div class="page">
<Header
:page-type="getType(searchKey.tab)"
ref="head"
:fix-head="true"
:need-add="true"/>
<PostList
:items="postList"
ref="postlist"
v-if="postList.length>0" />
<GoToTop
ref="gototop"
:flag="flag"/>
</div>
</template>
<!-- 在方法中调用this.$refs即可获取到ref绑定的组件或者DOM -->
// 收起菜单
this.$refs.head.show = false;
子组件内调用父组件的方法
日常开发者经常会遇到多层级嵌套组件,并且需要在最里面的子组件触发最外面的父组件事件,这种情况下当然最好的做法其实还是使用Vuex进行管理,如果你的项目使用Vuex进行管理了,后面就没必要看了。Vuex的相关内容请自行百度查阅。
第一种:直接在子组件中通过this.$parent.event
来调用父组件的方法
这种方式可以无限级别的向上找父级,例如:this.$parent.$parent.$parent.$parent.event
,子组件也不需要props
属性接收父组件的方法,但是多层级的时候容易搞乱层级,.$parent
太多了
父组件
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod();
}
}
};
</script>
第二种:父组件把方法传入子组件中,在子组件里直接调用这个方法
父组件内调用子组件的时候需要显示的传入方法(注意:这里是用的:
传入方法),子组件还需要通过props
接收父组件传来的方法,否则也不可以调用,另外就是多层级的时候需要一层一层的往下传,这时候就比较繁琐
父组件
<template>
<div>
<child :fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
childMethod() {
if (this.fatherMethod) {
this.fatherMethod();
}
}
}
};
</script>
第三种:子组件里用$emit
向父组件触发一个事件名(注意:这里是用的@
传入方法),父组件监听这个事件名就行了,子组件不需要通过props
接收父组件传来的方法,否则也不可以调用,这种最好向上传递一层父级,否则也需要层层传递
父组件
<template>
<div>
<child @fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '@/components/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('fatherMethod');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
第四种:使用$emit
和 $on
配合传递事件
如果仅仅是父子一层,传递事件就使用第三种就可以了,如果多层传递或者是兄弟组件,还可以使用$emit
和 $on
配合,其原理就是new 一个vue实例,然后在父子组件引入这个实例,这样在子组件触发的事件就会在父组件监听到了,这就是网上说的eventBus。
新建一个bus.js
import Vue from 'vue';
export default new Vue();
在父子组件分别引入这个bus.js
import eventBus from 'bus';
在子组件触发事件
export default {
methods: {
childMethod() {
eventBus.$emit('fatherMethod');
}
}
};
在父组件监听事件
export default {
mounted() {
//如果出现多次监听,肯定是没有解绑,可以在监听之前解绑,也可以在进入到这个路由或者渲染组件时候解绑一下就好了
eventBus.$off('fatherMethod');
eventBus.$on('fatherMethod');
}
};
当然如果你觉得建一个bus.js
文件多余的话,可以在main.js
里把bus
加到原型上
//vue原型链挂载总线
Vue.prototype.eventBus = new Vue();
加到原型上的好处就是全局都可以使用了
this.eventBus.$emit('fatherMethod');
this.eventBus.$on('fatherMethod');
引入vant
全局引入组件
import Vue from 'vue';
import { Toast } from 'vant';
Vue.use(Toast);
引入 Toast 组件后,会自动在 Vue 的 prototype 上挂载 $toast 方法,便于在组件内调用。
export default {
mounted() {
this.$toast('提示文案');
},
};
当然也可以在组件内引入
import { Toast } from 'vant';
组件内使用
export default {
mounted() {
Toast('第一个 Toast');
},
};
绑定、解绑节流函数
只要紧记绑定和解绑的事件是同一个就行了,如果不是一个,就单写成一个函数
export default {
mounted() {
//执行绑定函数事件
this.addScrollData();
},
methods: {
// 滚动加载数据
getScrollData: utils.throttle(function() {
// 节流getScrollTop
this.getScrollTop();
},300),
// 绑定滚动加载数据事件
addScrollData(){
//当然你也可以把上面的这个getScrollData写在这个函数里
this.getScrollData = utils.throttle(function() {
// 节流getScrollTop
this.getScrollTop();
},300);
// 绑定滚动加载数据事件
window.addEventListener('scroll', this.getScrollData);
}
},
//离开路由和组件销毁选择适合项目写一种解绑即可
// 离开路由之前
beforeRouteLeave(to, from, next){
// 解绑scroll事件
window.removeEventListener('scroll', this.getScrollData);
next();
},
//组件销毁之前
beforeDestroy () {
// 解绑scroll事件
window.removeEventListener('scroll', this.getScrollData);
},
};
vuex使用
在 http.js
使用store
import Store from '@/store';
import { SHOW_LOADING, HIDE_LOADING } from "@/store/mutationTypes.js";
...
...
...
Store.commit(SHOW_LOADING);
在组件内使用
this.$store.commit(SHOW_LOADING);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具