vue响应式数据的原理-vue最大的特点就是数据驱动视图,vue的数据改变,页面一定发生改变吗?这也不一定。当操作引用类型的数据,动态添加属性时,页面不会发生改变。vue响应式的原理:底层是Object.defineProperty(),目前vue2.6和将来的vue3.0都是通过给data中的数据加一个数据劫持,就是setter和getter方法,但是不管是哪种版本,ie浏览器都有兼容性问题,vue2.6不兼容ie8及以下,vue3.0不兼容ie11。被Object.defineProperty()处理过的数据,数据就会添加上get和set方法,数据获取的时候触发get,数据修改的时候触发set。在修改数据的时候,优先触发set,触发watch监听,再通知界面。vue中如果动态添加属性,该属性就没有经历过处理,就没有set和get方法,所以数据变页面不变。vm.$set()可以添加响应式属性,会触发视图的更新。
vue开发过程中踩过的坑:
swiper不轮播
swiper循环轮播loop:true失效---加v-if
portfinder1.0.22版本端口号失效
e对象不写()就是默认传e,如果写了()而没有传$event的话就拿不到e
路由变化而页面没有改变,使用watch监听或者beforeRouterUpdate()
vue和react的区别
数据:vue具有双向数据绑定和单向数据流。双向数据绑定:DOM元素绑定的data值,当发生改变后,vue的响应机制会自动监听data的变化重新渲染。单向数据流:当父组件给子组件传递数据的时候,子组件只可以读取而不能修改数据,可以用watch监听数据的更改,再赋给父组件的变量。react是单项数据流,DOM元素依赖于state,但改变state不会改变渲染好的DOM,通过setState()才能重新渲染。父组件传值到子组件,如果顶级的props变了,会重新渲染所有的子组件。
虚拟DOM:vue计算出DOM的差异,在渲染的过程中跟踪每个组件的依赖关系,不会重新渲染整个组件树。而react当应用的状态发生改变时,重新渲染全部子组件,可以通过shouldComponentUpdate生命周期进行优化。
模板和jsx:vue具有单文件组件,可以把html、css、js写在一个vue文件里---MVVM框架。react依赖于jsx,在JavaScript中创建DOM---视图层框架。
构建工具:vue-vue-cli。react-create-react-app 项目名
团队支持:vue是尤雨溪个人目前和阿里合作,react是Facebook维护。
vue指令-指令的生命周期:bind()--inserted()--update()--componentUpdate()--unbind()
v-text
v-html
v-show
v-if
v-else
v-else-if
v-for
v-on
v-bind
v-model
v-slot---命名插槽
v-pre---不需要表达式,跳过大量没有指令的节点,会加快编译
v-cloak---配合[v-cloak] { display: none },不显示{{}},如果没有彻底解决,则在根元素上加上style="display:none;" :style="{display:block}"
v-once---值渲染元素和组件一次,元素和组件及其所有子节点都将被视为静态内容并跳过,可以用于优化性能
vue全局API
Vue.extend()---将ui组件转换为js组件
Vue.nextTick()---数据更新后最新的DOM
Vue.set()---向响应式对象中添加一个响应式属性
Vue.delete()---删除对象的属性,如果对象是响应式的,确保删除能触发更新
Vue.directive(指令名,指令的配置项)---自定义指令
Vue.filter("名字",()=>{})---过滤器,管道符进行使用
Vue.component()---注册全局组件
Vue.use()---安装vue.js插件,如果插件是一个对象,必须提供install方法,如果插件是一个函数,那么它会被视为install方法
Vue.mixin()---混入,给当前组件额外扩展一些属性和方法,它的配置项和new Vue()的配置项一样
Vue.version()---判断当前vue版本var version=Number(Vue.version.split(".")[0])
vue修饰符
.lazy----<input type="text" v-model.lazy="value">----在光标离开后input框才会更新数据
.trim----<input type="text" v-model.trim="value">----输入框过滤首尾的空格
.number----<input type="text" v-model.number="value">----加了number修饰符后,如果先输入的是数字,表示这个输入框只能输入数字,如果先输入了字符串,等于这个输入框没有加number修饰符,所以这个修饰符就是个垃圾,还是得用正则判断
事件修饰符:
.stop----<button @click.stop="test"></button>----阻止事件冒泡
.prevent----<a @click.prevent="test"></a>----组件浏览器默认事件
.self----<div @click.self="test"></div>----只有点击到元素本身才会触发----bug:@click.self阻止了自身的点击,必须要点击到padding区域才行
.once----<div @click.once="test"></div>----只有第一次点击有效
.capture----<div @click.capture="test(1)"> <button @click="test(2)">test</button></div>----先1后2----事件机制是捕获-目标-冒泡,capture是倒过来
.passive----<div v-on:scroll.passive="onScroll">...</div>----滚动事件会立即触发,每次滚动都有一个默认事件触发,加了passive就是告诉浏览器,不需要查询,不需要触发这个默认事件
.native----<My-component @click.native="test"></My-component>----给组件绑定原生事件,给vue组件绑定事件的时候,必须加上 .native ,否则会认为监听的是来自子组件自定义的事件,等同于在子组件内部处理click事件后向外发送click事件($emit())
.left .right .middle----<button @click.right="test">test</button>----鼠标点击的时候触发
按键修饰符:.enter .esc .left .right .up .dowm .tab .delete .scape----<input type="text" @keyup.enter="test">
.keyCode----<input type="text" @keyCode(13)="test">
vue组件传值
1、父传子-props
2、子传父-$emit()
3、非父子:①给vue原型上添加一个公共的vue实例对象,使用$on()和$emit()进行接收和传递。②手动封装事件订阅observer。③事件总线EventBus。④vuex⑤如果是亲兄弟传值可以用父元素做周转。⑥provide/inject(提供/注入)跨组件传值,父传子孙。⑦插槽作用域(子传父)
vue路由传值-动态路由传值,加上props:true就可以用路由解耦、query、params。动态路由传值的时候,值是必须要传递的,要不然路由打不开,query传值的时候值不是必须要传递的。
vue路由的配置项-routes-path、component、redirect、children、meta、props、name、immediate:true
路由守卫-路由的生命周期-路由导航钩子-全局前置守卫beforeEach()、局部守卫beforeRouterEnter()、beforeRouterUpdate()、beforeRouterLeave()、路由独享守卫beforeEnter()直接在路由表中定义
路由懒加载-vue异步组件require()、ES6的import、webpack提供的require.ensure()---使用异步组件会将每个组件都生成一个js文件,import指定相同的webpackChunkName会合并打包成一个js文件,require.ensure()多个路由指定相同的chunkName,会合并打包成一个js文件。
vue过渡动画-transition-enter、enter-active、enter-to、leave、leave-active、leave-to,还可以搭配animate.css使用
computed和watch
$route和$router和routes的区别-$route是当前路由跳转对象,可以获取当前路由的name、path、query、params、hash、fullpath等。$router是路由的实例对象,编程式导航的跳转。routes是路由表,是一个数组,里面写路由的配置项。
less和sass的区别-less基于js,sass基于ruby,sass的环境较复杂,功能更多,less支持css语句,入手更简单,sass定义变量用$,less定义变量用@
vue UI框架:
vue-awesome-swiper-和swiper插件一样,用户操作之后停止轮播的bug,autoplay设置为一个对象,有个参数disableOnInteraction值默认为true,将它设置为false。循环轮播失效是因为循环还没有结束的时候swiper组件运行冲突出错导致的,可以添加v-if属性进行判断
mintUI-需要新建 .babelrc文件
vant-babel.config.js文件中添加plugins配置项
cubeUI-cmd安装,不需要在main.js中引入可以直接使用
elementUI-需要安装按需引入插件:babel-plugin-component,配置babel.config.js文件中的plugins配置项
iview
vue-lazyload图片懒加载-npm i vue-lazyload,v-lazy替换 :src
封装loading JS组件-先将html和css写好,再用Vue.extend()继承UI组件,实例化这个JS组件,返回一个对象,对象中有show()和hide(),使用的时候直接用对象.show()或对象.hide()
better-scroll二次封装、scrollTo()、上拉下拉-pullingUp和pullingDown事件,pullUpload和pullDownRefresh设置为true,finishPullUp()和finishPullDown()方法告诉better-scroll可以进行下一次的上拉和下拉,refresh()方法使DOM渲染正确。父组件访问子组件中的方法:this.$refs.BScroll.scrollTo()
搜索组件的封装-watch监听将每次输入框里的变化都拿来当做参数进行数据请求
input节流-在utils中封装成throttle(),传入一个回调,设置默认300ms调用一次,使用的时候用throttle()直接将原来请求的代码包裹,可以根据需求传入节流时间
vant框架tab切换动画
localStorage二次封装
vuex-只要用了vuex,input标签中就不能使用v-model,因为v-model的原理是直接修改数据,而vuex中要求修改数据在mutations中。如果不涉及到异步,可以在组件中直接触发commit()。input事件是每次输入框变化时都会执行,change事件是在输入框操作完后,按下回车键才会执行。事件函数如果不写(),就是不传参数,此时方法中可以直接接收到e对象,如果写了(),而没有手动传递$event,此时方法中就拿不到e对象。在组件中使用state中的值时,如果是标签中使用可以直接获取到$store,可以省略this,但是在js代码中使用$store不可以省略this。辅助函数:mapState、mapGetters、mapActions、mapMutations---前两个映射到computed中,后两个映射到methods中。modules配置项是多个合作开发的时候建立一个个小型的vuex,在使用的时候,如果是属性需要在前面加上模块名.,如果是方法需要在前面加模块名/。
vuex修改数据的流程-组件中用dispatch()去触发actions中的方法,actions中的方法({commit},params)通过解构commit后用commit()触发mutations中的方法(state,params),mutations中的方法去修改state中的数据,数据是响应式的,数据变页面变
json-server-先安装(npm i json-server),再使用(json-server goods.json)
mock数据-mock.mock(//users/list/,"get",(options)=>{return data})
----id---------"id|+1":0
----name-----"name":"@cname"
----tel---------"tel":/^1(3|5|7|8|9)d{9}$/
----imgUrl----"imgUrl":"@image('600x400','#000','#fff','png','孙艺珍')"
----address---"address":"@county(true)"
----date-------"date":"@datatime('yyyy-MM-dd A HH:mm:ss')"
----desc-------"desc":"@cparagraph(1,5)"
----list---------"list|5":[{},{},{}]