Vue核心技术总结
2020-04-09 17:44:27 4 举报
AI智能生成
vue全家桶 vue vue-router vuex SSR
作者其他创作
大纲/内容
Vue核心知识
实例
实例属性
$el
$render //页面重新渲染的时候触发
$date
$mount
$props
$options //在此设置data的值是不会生效的。
$children
$root
$slots
$refs
$isServer
$render //页面重新渲染的时候触发
$date
$mount
$props
$options //在此设置data的值是不会生效的。
$children
$root
$slots
$refs
$isServer
实例方法
$watch和实例里的watch属性是一样的。区别是,$watch需要手动注销。
$on,$emit 事件的接受和触发在同一个实例上才会生效
$once事件只执行一次。
$forceUpdate(),强制渲染
$set(app.obj, 'a','123') //新增属性a并赋值
$delete可以彻底把属性删掉
vm.$nextTick([callback]) //下一次渲染的时候,执行
$on,$emit 事件的接受和触发在同一个实例上才会生效
$once事件只执行一次。
$forceUpdate(),强制渲染
$set(app.obj, 'a','123') //新增属性a并赋值
$delete可以彻底把属性删掉
vm.$nextTick([callback]) //下一次渲染的时候,执行
$set, $forceUpdate()
使用场景
使用场景
问题
vue实例的data中有一个obj:{},
给obj的属性新增属性,值会改变,但是不会重新渲染
给obj的属性新增属性,值会改变,但是不会重新渲染
原因
因为 vue 无法监听新增的属性,只能监听你修改属性,除非你开始就指定了相关属性,哪怕是 undefined.
解决办法
$forceUpdate()
强制重新渲染
$set()
Vue.set( target, propertyName/index, value )
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。
它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = 'hi')
它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = 'hi')
https://cn.vuejs.org/v2/api/#Vue-set-target-propertyName-index-value
参考
$set,$delete,$forceUpdate()的使用
https://www.jianshu.com/p/7412bea4e720
https://www.jianshu.com/p/7412bea4e720
1.$set给data对象中的变量设置值,比如我在data中定义了一个对象,在使用的时候我想给这个对象赋予一个a的属性,
var app = new Vue({
el:"#main",
template:'<div>{{obj.a}}</div>'
data:{
obj:{}
}
})
var i=0;
i++;
app.$set(app.obj,'a',i)
语法糖[vm.$set( target, key, value )]
2、$delete删除对象的属性
app.$delete(app.obj,'a')
3、$forceUpdate()强行更新vue实例
在data中声明了obj对象,但并没有a的声明
setInterval(()=>{
var i=0;
i++;
app.obj.a=i;
},1000)
console.log(app.obj.a)
但是在页面中并不会显示出a的值,但是a的值在一直改变,console会打印出来,这中方法a的值并没有在data中事先声明,不能显示在页面,如果想显示出来,也可以在声明obj的时候,给a声明一个空值。
在data中声明的对象的属性并没有声明,但是调用了,这是非响应式,不会重新渲染
方法二:
使用app.$forceUpdate(),强行更新vue实例
var app = new Vue({
el:"#main",
template:'<div>{{obj.a}}</div>'
data:{
obj:{}
}
})
setInterval(()=>{
var i=0;
i++;
app.$forceUpdate(app.obj,'a',i)
},1000)
console.log(app.obj.a)
$forceUpdate该方法会重新给obj的a属性重新声明,在页面就能显示出来了,但是这种方法不建议使用,如果要使用到a的值,可以先声明一个空值
var app = new Vue({
el:"#main",
template:'<div>{{obj.a}}</div>'
data:{
obj:{}
}
})
var i=0;
i++;
app.$set(app.obj,'a',i)
语法糖[vm.$set( target, key, value )]
2、$delete删除对象的属性
app.$delete(app.obj,'a')
3、$forceUpdate()强行更新vue实例
在data中声明了obj对象,但并没有a的声明
setInterval(()=>{
var i=0;
i++;
app.obj.a=i;
},1000)
console.log(app.obj.a)
但是在页面中并不会显示出a的值,但是a的值在一直改变,console会打印出来,这中方法a的值并没有在data中事先声明,不能显示在页面,如果想显示出来,也可以在声明obj的时候,给a声明一个空值。
在data中声明的对象的属性并没有声明,但是调用了,这是非响应式,不会重新渲染
方法二:
使用app.$forceUpdate(),强行更新vue实例
var app = new Vue({
el:"#main",
template:'<div>{{obj.a}}</div>'
data:{
obj:{}
}
})
setInterval(()=>{
var i=0;
i++;
app.$forceUpdate(app.obj,'a',i)
},1000)
console.log(app.obj.a)
$forceUpdate该方法会重新给obj的a属性重新声明,在页面就能显示出来了,但是这种方法不建议使用,如果要使用到a的值,可以先声明一个空值
$nextTick()
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
https://cn.vuejs.org/v2/api/#Vue-nextTick
生命周期
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured
errorCaptured
可以向上冒泡,能够捕获组件自身和子组件中的render异常
可以使用在生产环境
可以使用在生产环境
数据绑定
:class
:style
v-html
:style
v-html
:class
https://cn.vuejs.org/v2/guide/class-and-style.html
语法
对象语法
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
数组语法
<div v-bind:class="[activeClass, errorClass]"></div>
混合
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
computed和watch
computed
当app里面的任意属性发生变化时,template会重新渲染。当template通过computed方法获取值时,只有computed 监听的属性发生变化时,才会重新调用函数,否则computed会取缓存里面的值; 当template是通过methods里面的方法获取值时,只要app的任意属性发生变化,都会调用函数。所以,template相对于通过methods里面的方法获取值,通过computed获取值性能会更高。
watch
immediate:true
先执行一遍监听,而不用等数据发生变化再监听
deep:true
wacth想监听对象内部属性变化时,可以使用deep:true 或者 换成字符串格式监听:obj.a -> 'obj.a',推荐使用后者
注意
尽可能不要修改wacth和computed的值,避免造成死循环。
原生指令
常用指令
v-bind: 可缩写为:,绑定某个属性
v-on 可缩写@,绑定某个事件
v-on 可缩写@,绑定某个事件
v-text,绑定标签的文本,标签内部只能显示绑定的值,不如{{}}灵活
v-html,把变量的内容作为html插入节点
v-html,把变量的内容作为html插入节点
v-if,根据值来定义节点,节点不存在,只是被加入或删除,动态增删节点
v-if-else 和if结合使用
v-else 和if结合使用,最终不符合情况的结果
v-if-else 和if结合使用
v-else 和if结合使用,最终不符合情况的结果
v-show,赋值bool来,显示/隐藏节点,节点本来存在,只是被隐藏了,其实就是在节点上加display
v-for
v-for='(item,index) in arr'
v-for='(val,key,index) in obj'
:key
v-model
在input上使用
修饰符
.number
.lazy
.trim
其他不常用指令
v-pre
v-cloak
v-once
首次渲染后,即使数据发生变化,也不会被重新渲染。一般用于静态内容展示。
组件
定义
组件定义
components里,用PascalCase形式
使用自定义的组件时,用kebab-case形式
组件定义的data
data必须是function
props
定义时,用PascalCase形式
使用时,用kebab-case形式,这种形式比较规范
也可以写PascalCase形式,遵循团队编码规范即可
也可以写PascalCase形式,遵循团队编码规范即可
注意
不能直接修改prop
继承
extend
this.$parent
this.$parent.$options.name
this.$parent.data1
获取修改父组件的内容,
最好不要修改,容易造成逻辑混乱,多层渲染
this.$parent.data1
获取修改父组件的内容,
最好不要修改,容易造成逻辑混乱,多层渲染
双向绑定
v-model
高级属性
<slot>插槽
具名插槽 name
作用域插槽 slot-scope
provide 祖先组件
inject 子孙组件
inject 子孙组件
render function
render function
name可以是组件名字,也可以是dom节点
props 可以传递attr ref等
render(createElement) {
return createElement('name', {props}, [子组件])
}
return createElement('name', {props}, [子组件])
}
三种写组件方式:
template
render function
jsx
Vue-Router
vue-router的使用
routes
routes
/ 是默认路由
router
router
使用vue-router
Vue.use(VueRouter)
<router-view>
展示路由的页面
展示路由的页面
<router-view>
匹配到的路由页面,会展示在router-view里
命名路由
在.vue文件中引入多个<router-view>时可以使用name命名
<router-view name="aaa"/>
在routes.js文件中写路由compnents:{default:组件一,aaa:组件二}
<router-view name="aaa"/>
在routes.js文件中写路由compnents:{default:组件一,aaa:组件二}
Router构建选项
mode:'history'
mode:'history'
默认是hash模式
mode:'history'可以去掉#
mode:'history'可以去掉#
base
设置基路径
跳转后,路由前会加上/base/,不加也可以
跳转后,路由前会加上/base/,不加也可以
linkActiveClass:
linkExactActiveClass:'
linkExactActiveClass:'
链接被激活时显示什么样式
scrollBehavior(to, from,savedPosition){}
定义路由跳转时的滚动行为
parseQuery(query){}
stringifyQuery(obj){}
stringifyQuery(obj){}
处理url中的query
路由项
name
给路由命名
meta
页面元信息
保存路由里的一些信息
可以通过route.meta获取
保存路由里的一些信息
可以通过route.meta获取
children
子路由
路由传参
/:id
动态路由
动态路由
通过this.$route.params.id获得
通过配置
props: true
获得
props: true
获得
id会自动传到Todo组价里
在Todo组件里,通过props可以获取路由传递的id
?a=123
url参数
url参数
通过this.$route.query获得
路由导航守卫
全局导航守卫(钩子)
router.beforeEach(to, from, next) {}
使用场景:
用户登陆后页面才能显示页面,如果没登陆则跳转到登陆页面
router.beforeResolve(to, from, next) {}
router.afterEach(to, from) {}
路由独享钩子
即在路由配置时增加的钩子
即在路由配置时增加的钩子
beforeEnter(to, from,next){ next() }
页面路由钩子
即组件内钩子
即组件内钩子
beforeRouteEach (to,from,next){}
在页面创建之前,拿不到this,可以在next()回调中获取
beforeRouteUpdate(to,from, next){}
使用动态路由时,路由切换时触发
用途
可以用这个钩子获取动态路由
beforeRouteLeave(to, from,next)
使用场景
判断是否离开页面
比如用户修改表单时,不小心点了额外的链接,弹出提示让用户确认是否要离开,可以避免误操作导致的修改的表单内容丢失
比如用户修改表单时,不小心点了额外的链接,弹出提示让用户确认是否要离开,可以避免误操作导致的修改的表单内容丢失
Vuex
如何使用vuex
安装
npm install vuex -S
声明一个简单的store
store.js
引入
引入
import Vuex from 'vuex'
import createStore from './store/store'
Vue.use(Vuex)
const store = createStore()
在应用的入口中注入store
调用
使用、修改store中的state
更合理的store结构
&
各部分的实现
&
各部分的实现
拆分后的目录
state.js
state.js
把所有初始数据声明到state.js里
getters.js
getters.js
vuex中的getters相当于vue中的computed
用来组装数据,比如从后端的获取的数据不能直接展示在view里,可以用getters进行数据的组装
组装的数据在多个页面都要使用,如果写在computed中进行组装,就要进行重复劳动,而且后期不好维护
组装的数据在多个页面都要使用,如果写在computed中进行组装,就要进行重复劳动,而且后期不好维护
mutations.js
mutations.js
作用
mutation是专门用于修改state中的数据的
修改state的方法
使用mutation修改
vue 官方推荐,所有的state修改都放到mutation中
可以规范数据的修改
可以规范数据的修改
在组件中直接修改
在mutation之外修改,但是这种方式不推荐使用
使用this.$store.state修改state
参数
第一个
state
第二个
第二个参数即Payload,它是object类型
https://vuex.vuejs.org/zh/guide/mutations.html#%E6%8F%90%E4%BA%A4%E8%BD%BD%E8%8D%B7%EF%BC%88payload%EF%BC%89
https://vuex.vuejs.org/zh/guide/mutations.html#%E6%8F%90%E4%BA%A4%E8%BD%BD%E8%8D%B7%EF%BC%88payload%EF%BC%89
action.js
action.js
参数
第一个
store
第二个
Payload
store.js
拆分后的store.js
strict
strict:true 限制在mutation之外对state进行修改
用于开发环境,可以规范大家的代码
在mutation之外修改state会警告
拆分的好处:当action和mutations变多时,拆分到各自的文件中有利于后期维护
如何使用store
state和getters
使用this.$store
获取state和getters
获取state和getters
使用this.$store
this.$store.state
this.$store.getters
这种写法太麻烦
this.$store.getters
这种写法太麻烦
使用mapState和mapGetter
获取state和getters
获取state和getters
引入
mapState()
使用方式
数组
mapState()接受一个数组,数组中的'count'是state.js中的初始数据count
适用于同名的情况
适用于同名的情况
对象
mapState()接受一个对象,获取state.js中的初始数据count并把它重命名为counter
适用于重命名的情况
适用于重命名的情况
方法
适用于需要做一些计算的情况
作用
可以更便捷的使用state的数据
mapGetters
使用方式
和mapState相同
作用
可以更便捷的使用getter中的数据
mutation和action
区别
mutation用于同步修改数据
action用于异步修改数据, 比如数据请求时
action用于异步修改数据, 比如数据请求时
使用this.$store触发
mutation和action
mutation和action
触发mutation
使用this.$store.commit触发mutation
触发action
使用this.$store.dispatch触发action
使用mapMutation和mapAction
触发mutation和action
触发mutation和action
引入
在methods中引入mutation和action方法
调用action方法
作用
可以更便捷的调用mutation和action方法
模块
模块是什么?
Vuex 允许我们将 store 分割成模块(module)。
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
https://vuex.vuejs.org/zh/guide/modules.html#module
声明模块
声明模块a和b
模块的局部状态
mutation和getter的第一个参数
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象state
getter第三个参数
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来,即rootState
使用rootState,可以在模块内部获取全局state
使用rootState,可以在模块内部获取全局state
action参数
对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState:
{root:true}的作用
action默认会在当前模块内部寻找mutation,
使用{root:true}可以在模块内部调用全局空间的mutation
使用{root:true}可以在模块内部调用全局空间的mutation
调用
使用模块中的state
直接使用
在mapstate中使用
调用模块中的getter
在mapGetter中调用
调用模块中的action
调用局部action
命名空间
namespaced: true
可以在不同的模块中使用相同的变量名、方法名
动态注册模块
动态注册一个模块c
热更替
hotUpdate
hotUpdate
热更替
作用
当修改了state时,不使用热更替的话,页面会刷新
使用热更替,修改的内容会直接更新到页面上,不会刷新页面
使用热更替,修改的内容会直接更新到页面上,不会刷新页面
一些其他的API
和配置
和配置
store.watch
watch(fn: Function, callback: Function, options?: Object): Function
响应式地侦听 fn 的返回值,当值改变时调用回调函数。fn 接收 store 的 state 作为第一个参数,其 getter 作为第二个参数。最后接收一个可选的对象参数表示 Vue 的 vm.$watch 方法的参数。
要停止侦听,调用此方法返回的函数即可停止侦听。
响应式地侦听 fn 的返回值,当值改变时调用回调函数。fn 接收 store 的 state 作为第一个参数,其 getter 作为第二个参数。最后接收一个可选的对象参数表示 Vue 的 vm.$watch 方法的参数。
要停止侦听,调用此方法返回的函数即可停止侦听。
https://vuex.vuejs.org/zh/api/#watch
示例
监听state中值的变化
store.subscribe
subscribe(handler: Function): Function
订阅 store 的 mutation。handler 会在每个 mutation 完成后调用,接收 mutation 和经过 mutation 后的状态作为参数:
订阅 store 的 mutation。handler 会在每个 mutation 完成后调用,接收 mutation 和经过 mutation 后的状态作为参数:
https://vuex.vuejs.org/zh/api/#subscribe
示例
监听mutation的调用
store.subscribeAction
subscribeAction(handler: Function): Function
订阅 store 的 action。handler 会在每个 action 分发的时候调用并接收 action 描述和当前的 store 的 state 这两个参数:
订阅 store 的 action。handler 会在每个 action 分发的时候调用并接收 action 描述和当前的 store 的 state 这两个参数:
https://vuex.vuejs.org/zh/api/#subscribeaction
示例
监听action的调用
plugins
plugins
一个数组,包含应用在 store 上的插件方法。这些插件直接接收 store 作为唯一参数,可以监听 mutation(用于外部地数据持久化、记录或调试)或者提交 mutation (用于内部数据,例如 websocket 或 某些观察者)
https://vuex.vuejs.org/zh/api/#plugins
图解vuex
子主题
newVue
渲染App
Route
在App中注册子组件
注入Store
可以使用$store把App和Store关联起来
dispatch commit
使用dispatch和commit触发store中state的修改
SSR
服务端渲染构建流程
服务端渲染构建流程
webpack dev server :使用热更替等其他功能,加快开发速度,但是无法添加服务端渲染的代码
node server: 执行服务端渲染的逻辑,使用vue的vue server rander 在node 环境中渲染出html代码,并返回给用户
node server: 执行服务端渲染的逻辑,使用vue的vue server rander 在node 环境中渲染出html代码,并返回给用户
KOA实现node server
掌握node基础知识后再看服务端渲染
高级组件开发
notification
实现基础组件
notification.vue
全局引入组件
import Notification from './components/notification'
Vue.use(Notification)
全局注册组件和方法
Vue.component(Notification.name, Notification);
全局注册组件,在整个全局都可以使用这个component
Vue.prototype.$notify = notify;
把notify方法放到vue.prototype中,使得可以全局调用。
实现API
父类
import Notification from './notification.vue'
notification.vue
notify传递的参数,会传到props里
notify传递的参数,会传到props里
func-notification.js
notify()实现
定义方法notify
方法notify,参数options
实例
NotificationConstructor
是组件父类Component的组件构造器
是组件父类Component的组件构造器
变量是notify中的options解构来的
行为
挂载显示
计算各个实例的偏移
弹窗消失
在父类中,
挂载时,设置定时器
销毁时,清除定时器
挂载时,设置定时器
销毁时,清除定时器
弹窗消失后删除dom节点
减小内存消耗
减小内存消耗
绑定id
const id = `notification_${seed++}`
instance.id = id
instance.id = id
删除
根据id删除dom,并调整offset
删除某个节点后,调整该节点上方节点的位置
调用
API的形式调用组件,传递参数
具体实现看/Users/sunhonghong/Downloads/coding-196/client/components/notification
Tab组件实现
组件结构设计
Tab组件结构
渲染后的结构
组件各部分设计
Tabs
Tab
TabContainer
行为
确定哪个Tab被选中
$parent
Tab的index和Tabs中的value相等时,该Tab被选中
数据传递的方式
祖先组件 ,传递数据 provide()
子孙组件,获取数据inject
子孙组件,获取数据inject
不是响应式的
使用Object.defineProperty解决
使用Object.defineProperty解决
$parent
不适合Tabs和Tab跨层级时
点击切换标签
子组件给父组件传递数据
子组件Tab
当Tab被点击时
Tab传递它的index给父组件Tabs的onChange方法
Tab传递它的index给父组件Tabs的onChange方法
父组件接受子组件传来的数据
父组件Tabs
Tab接收Tab传来的数据,并将该数据发射给自定义事件change
在调用Tabs组件处,监听自定义事件change,并修改value值
调用
自定义事件change监听到Tabs传来的数据
修改value
修改tabValue,Tabs中的value随之改变,Tab就切换了
处理标签内容
将所有标签的内容全部展示出来
子组件
父组件
pane.$slot.default
在父组件中渲染子组件的slot
在父组件中渲染子组件的slot
筛选对应的内容
只展示选中标签对应的内容
注意
slot不是reactive的
输入input,输入的内容展示会慢一拍,
这是因为Tabs认为props和data并没有改变,所以不会重新渲染
将pane相关的内容都抽离到Tab-container里
这是因为Tabs认为props和data并没有改变,所以不会重新渲染
将pane相关的内容都抽离到Tab-container里
tabs
tab-container
具体实现,看/Users/sunhonghong/Downloads/coding-196/client/components/tabs
项目开发
0 条评论
下一页