vue 作为目前前端三大框架之一,对于前端开发者可以说是必备技能。那么怎么系统地学习和掌握 vue 呢?为此,我做了简单的知识体系体系总结,不足之处请各位大佬多多包涵和指正,如果喜欢的可以点个小赞!本文主要讲述一些vue开发中的实用技巧。
比如有父组件 Parent 和子组件 Child,如果父组件监听到子组件挂载 mounted 就做一些逻辑处理,常规的写法可能如下:
// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
this.$emit("mounted");
}
此外,还有一种特别简单的方式,子组件不需要任何处理,只需要在父组件引用的时候通过@hook 来监听即可,代码如下:
<Child @hook:mounted="doSomething" />
<Child @hook:updated="doSomething" />
当然这里不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以。
观察和响应 Vue 实例上的数据变动。类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作。
但是当 watch 一个变量的时候,初始化时并不会执行,如下面的例子,你需要在 created 的时候手动调用一次。
created() {
this.getList();
},
watch: {
keyWord: 'getList',
}
上面这样的做法可以使用,但很麻烦,我们可以添加 immediate 属性,这样初始化的时候就会自动触发(不用再写 created 去调用了),然后上面的代码就能简化为:
watch: {
keyWord: {
handler: 'getList',
immediate: true
}
}
watch 有三个参数
同一path的页面跳转时路由参数变化,但是组件没有对应的更新。
原因:主要是因为获取参数写在了created或者mounted路由钩子函数中,路由参数变化的时候,这个生命周期不会重新执行。
解决方案1:watch监听路由
watch: {
// 方法1 //监听路由是否变化
'$route' (to, from) {
if(to.query.id !== from.query.id){
this.id = to.query.id;
this.init();//重新加载数据
}
}
}
//方法 2 设置路径变化时的处理函数
watch: {
'$route': {
handler: 'init',
immediate: true
}
}
解决方案2 :为了实现这样的效果可以给router-view添加一个不同的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。
<router-view :key="$route.fullpath"></router-view>
Vue 项目中实现路由按需加载(路由懒加载)的 3 中方式:
// 1、Vue异步组件技术:
{
path: '/home',
name: 'Home',
component: resolve => reqire(['path路径'], resolve)
}
// 2、es6提案的import()
const Home = () => import('path路径')
// 3、webpack提供的require.ensure()
{
path: '/home',
name: 'Home',
component: r => require.ensure([],() => r(require('path路径')), 'demo')
}
require.context(directory,useSubdirectories,regExp)
场景:如页面需要导入多个组件,原始写法:
import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components: {
titleCom, bannerCom, cellCom
}
这样就写了大量重复的代码,利用 require.context 可以写成
const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
const name = path.basename(key, '.vue')
modules[name] = files(key).default || files(key)
})
components: modules
<template>
<div v-for="(item,index) in treeArr"> {{index}} <br/>
<tree :item="item.arr" v-if="item.flag"></tree>
</div>
</template>
<script>
export default {
// 必须定义name,组件内部才能递归调用
name: 'tree',
data(){
return {}
},
// 接收外部传入的值
props: {
item: {
type:Array,
default: ()=>[]
}
}
}
</script>
由于项目中有些页面难免会碰到需要定时器或者事件监听。但是在离开当前页面的时候,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况,这个时就需要清除定时器事件监听,即在页面卸载(关闭)的生命周期函数里,清除定时器。
methods:{
resizeFun () {
this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128
},
setTimer() {
this.timer = setInterval(() => { })
},
clearTimer() {//清除定时器
clearInterval(this.timer)
this.timer = null
}
},
mounted() {
this.setTimer()
window.addEventListener('resize', this.resizeFun)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeFun)
this.clearTimer()
}
我们也可以在基础配置文件中添加自己的路径别名
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'assets': resolve('src/assets')
}
}
然后我们导入组件的时候就可以这样写:
// import YourComponent from '/src/assets/YourComponent'
import YourComponent from 'assets/YourComponent'
这样既解决了路径过长的麻烦,又解决了相对路径的烦恼。
原因:因为我们在写.vue文件中的样式都会追加scoped。这样针对模板dom中的样式就可以生效,但其生效后的最终样式并不是我们写的样式名,而是编码后的。比如:
<template>
<div class="box">dom</div>
</template>
<style lang="scss" scoped>
.box {
background: red;
}
</style>
vue 将代码转译成如下,所以我们在js中拼接上的dom结构样式并不会生效。
.box[data-v-11c6864c]{ background:red; }
<template>
<div class="box" data-v-11c6864c>dom</div>
</template>
解决方法:将要改变的样式写在非scoped样式标签中。
我们应该都知道 vue 会通过 object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间。
所以,我们可以通过 object.freeze 方法来冻结一个对象,这个对象一旦被冻结,vue就不会对数据进行劫持了。
export default {
data: () => ({
list: []
}),
async created() {
const list = await axios.get('xxxx')
this.list = Object.freeze(list)
},
methods: {
// 此处做的操作都不能改变list的值
}
}
另外需要说明的是,这里只是冻结了 list 的值,引用不会被冻结,当我们需要 reactive 数据的时候,我们可以重新给 list 赋值。
插槽 slot,也是组件的一块 html 模板,这一块模板显示不显示、以及怎样显示由父组件来决定。实际上,一个 slot 最核心的两个问题在这里就点出来了,是显示不显示和怎样显示。
又名单个插槽、匿名插槽,这类插槽没有具体名字,一个组件只能有一个该类插槽。
<!-- 父组件 parent.vue -->
<template>
<div class="parent">
<h1>父容器</h1>
<child>
<div class="tmpl">
<span>菜单1</span>
</div>
</child>
</div>
</template>
<!-- 子组件 child.vue -->
<template>
<div class="child">
<h1>子组件</h1>
<slot></slot>
</div>
</template>
匿名插槽没有 name 属性,所以叫匿名插槽。那么,插槽加了 name 属性,就变成了具名插槽。具名插槽可以在一个组件中出现 N 次,出现在不同的位置,只需要使用不同的 name 属性区分即可。
<!-- 父组件 parent.vue -->
<template>
<div class="parent">
<h1>父容器</h1>
<child>
<div class="tmpl" slot="up">
<span>菜单up-1</span>
</div>
<div class="tmpl" slot="down">
<span>菜单down-1</span>
</div>
<div class="tmpl">
<span>菜单->1</span>
</div>
</child>
</div>
</template>
<!-- 子组件 child.vue -->
<template>
<div class="child">
<!-- 具名插槽 -->
<slot name="up"></slot>
<h3>这里是子组件</h3>
<!-- 具名插槽 -->
<slot name="down"></slot>
<!-- 匿名插槽 -->
<slot></slot>
</div>
</template>
作用域插槽可以是默认插槽,也可以是具名插槽,不一样的地方是,作用域插槽可以为 slot 标签绑定数据,让其父组件可以获取到子组件的数据。
<!-- parent.vue -->
<template>
<div class="parent">
<h1>这是父组件</h1>
<child
>>
<template slot="default" slot-scope="slotProps">
{{ slotProps.user.name }}
</template> </child
>>
</div>
</template>
<!-- 子组件 child.vue -->
<template>
<div class="child">
<h1>这是子组件</h1>
<slot :user="user"></slot>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: '小赵'
}
}
}
}
</script>
一直以来进行了比较多的微信小程序开发... 总会接触到一些和官方组件或 api 相关或其无法解决的需求,于是决定在这里小小的整理一下微信小程序开发的一些技巧
小程序提供onShareAppMessage 函数,此函数只支持分享给我微信朋友,小程序如何分享到朋友圈呢?使用canvas绘制一张图片,并用wx.previewImage预览图片,然后长按图片保存图片到手机。
前端新手程序员不知道的 20个小技巧:作为前端开发者,使用双显示器能大幅提高开发效率、学编程最好的语言不是PHP,是English、东西交付之前偷偷测试一遍、问别人之前最好先自己百度,google一下、把觉得不靠谱的需求放到最后做,很可能到时候需求就变了...
本地的 IP 地址是分配给你计算机上的内部硬件或虚拟网卡的本地/私有 IP 地址。根据你的 LAN 配置,上述 IP 地址可能是静态或动态的。公共的 IP 地址是你的 Internet 服务提供商(ISP)为你分配的公共/外部 IP 地址。
使用 :not() 在菜单上应用/取消应用边框;给body添加行高;所有一切都垂直居中;逗号分隔的列表;使用负的 nth-child 选择项目;对图标使用SVG;优化显示文本;对纯CSS滑块使用 max-height;继承 box-sizing
禁用右键点击;禁用搜索文本框;新窗口打开链接;检测浏览器;预加载图片;样式筛选;列高度相同;字体大小调整;返回页面顶部;获取鼠标的xy坐标;验证元素是否为空;替换元素
为你网站的用户留下良好的第一印象是非常必要的。随着商业领域的竞争,拥有一个吸引人的网站可以帮助你脱颖而出。研究表明,如果加载时间超过3秒,会有 40% 的用户放弃访问你的网站
清除浮动主要用于子元素浮动(float)之后,父元素无法撑起高度和宽度。文字少时居中,多时靠左因为div嵌套着p,所以p的尺寸并不会超过div。但是要注意,当p的内容为英文单词组成的时候
这次我们主要来分享11个在日常教程中不常被提及的JavaScript小技巧,他们往往在我们的日常工作中经常出现,但是我们又很容易忽略。Set类型是在ES6中新增的,它类似于数组,但是成员的值都是唯一的
为什么要在JavaScript里写CSS?避免命名全局污染,条件和动态样式(比如选择主题色之类的),在框架层面进行限制或补充(比如补全供应商前缀),避免业务人员使用奇技淫巧
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!