vue 做为目前前端三大框架之一,对于前端开发者能够说是必备技能。那么怎么系统地学习和掌握 vue 呢?为此,我作了简单的知识体系体系总结,不足之处请各位大佬多多包涵和指正,若是喜欢的能够点个小赞!本文主要讲述一些vue开发中的实用技巧。css
相关推荐前端
总结vue 知识体系之基础入门篇
总结几个vue-router的使用技巧
搭建一个vue-cli的移动端H5开发模板vue
好比有父组件 Parent 和子组件 Child,若是父组件监听到子组件挂载 mounted 就作一些逻辑处理,常规的写法可能以下:react
// Parent.vue <Child @mounted="doSomething"/> // Child.vue mounted() { this.$emit("mounted"); }
此外,还有一种特别简单的方式,子组件不须要任何处理,只须要在父组件引用的时候经过@hook 来监听便可,代码以下:webpack
<Child @hook:mounted="doSomething" /> <Child @hook:updated="doSomething" />
固然这里不只仅是能够监听 mounted,其它的生命周期事件,例如:created,updated 等均可以。ios
观察和响应 Vue 实例上的数据变更。相似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操做。es6
可是当 watch 一个变量的时候,初始化时并不会执行,以下面的例子,你须要在 created 的时候手动调用一次。web
created() { this.getList(); }, watch: { keyWord: 'getList', }
上面这样的作法可使用,但很麻烦,咱们能够添加 immediate 属性,这样初始化的时候就会自动触发(不用再写 created 去调用了),而后上面的代码就能简化为:正则表达式
watch: { keyWord: { handler: 'getList', immediate: true } }
watch 有三个参数算法
handler
:其值是一个回调函数。即监听到变化时应该执行的函数deep
:其值是 true 或 false;确认是否深刻监听。immediate
:其值是 true 或 false,确认是否以当前的初始值执行 handler 的函数同一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 中方式:
// 一、Vue异步组件技术: { path: '/home', name: 'Home', component: resolve => reqire(['path路径'], resolve) } // 二、es6提案的import() const Home = () => import('path路径') // 三、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>
从零开始构建一个webpack项目
总结几个webpack打包优化的方法
总结前端性能优化的方法
几种常见的JS递归算法
封装一个toast和dialog组件并发布到npm
一文读尽前端路由、后端路由、单页面应用、多页面应用
浅谈JavaScript的防抖与节流
关注的个人公众号不按期分享前端知识,与您一块儿进步!