Vue
Vue基础
框架
什么是MVVM: MVVM 是 Model-View-ViewModel 的缩写。
Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
View 代表UI 组件,它负责将数据模型转化成UI 展现出来。
ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。
数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。 核心:数据驱动、组件化思想 单页面优缺点: 优点:Vue 的目标是通过尽可能简单地 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。
缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。
基础语法
模板语法: 1.文本:Message:{{msg}} 2.原始HTML 3.Attribute:
4.JavaScript:{{ message.split('').reverse().join('') }} class与style绑定: 1.2.3.<div v-bind:style="{color:activeColor, fontSize:fontSize+'px'}> 4.
条件渲染
v-if:
Vue is awesome!
Oh no
Woo
v-show:
Hello!
v-if vs v-show: v-if会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁、重建。且是惰性的,如果初始渲染条件为假,则什么也不做,直到条件第一次变真。 v-show:无论条件为什么,元素都会被渲染,只是简单地基于css变化。 v-if与v-for一同使用时,v-for有更高优先级。v-if会被应用于每个v-for循环中。
计算属性和侦听器
计算属性 var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 计算属性的 getter reversedMessage: function () { // this 指向 vm 实例 return this.message.split('').reverse().join('') } } })
侦听器: var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } })
列表渲染
例子:
- {{ item.message }}
就地更新策略:如果数据项的顺序改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。并且确保它们在每个索引位置正确渲染。 key:使用 key 来给每个节点做一个唯一标识,Diff 算法就可以正确地识别此节点,找到正确的位置区插入新的节点 所以一句话,key 的作用主要是为了高效的更新虚拟 DOM
事件处理
内联处理器:Say hi 需要在内联语句处理器中访问原始事件的DOM事件,可以使用特殊变量$event Submit methods: { warn: function (message, event) { // 现在我们可以访问原生事件对象 if (event) { event.preventDefault() } alert(message) } } 事件修饰符:
- 1. .stop阻止单击事件继续传播
- 2. .prevent提交事件不再重载页面
- 3. .capture添加事件监听器时使用事件捕获模式,内部元素的事件先在此处理,然后才交由内部元素进行处理
- 4. .self只当在event.target是当前元素自身时触发处理函数,事件不是从内部触发的
- 5. .once点击事件将只会触发一次
- 6. .passive对应addEventListener中的passive,不能与.prevent一起使用,.prevent会被忽略。
...
- 1. 按键修饰符 keyup.enter keyup.page-down 8)按键码:keyup.f1 9)系统修饰符:.ctrl, .alt, .shift, .meta 10)鼠标修饰符:.left, .right, .middle
表单输入绑定v-model
修饰符:
- 1. .lazy: 在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步
- 2. .number: 自动将用户的输入值转为数值类型
- 3. .trim: 自动过滤用户输入的首尾空白字符
组件
插槽 具名插槽:
A paragraph for the main content.
And another one.
动态组件、异步组件
动态组件保持状态:keep-alive
异步组件:。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。 new Vue({ // ... components: { 'my-component': () => import('./my-async-component') } })
父子组件
方法调用: 1)父组件调用子组件方法
子组件
2)子组件调用父组件: 父组件:
子组件:
通信: 1)父传子 父组件:prop单向数据流,父级prop的更新会向下流动到子组件中,反过来不行。这样会防止从子组件意外变更父级组件的状态。
子组件:
2)子传父 父组件:
自定义事件
自定义组件的v-model:一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突 Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean }, template: <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > }) 将原生事件绑定至组件: 1. 2.$listener 3. .sync
生命周期
生命周期:beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed 父子组件生命周期: 1.父组件:beforeCreate->created->beforeMount 2.子组件:->beforeCreate->created->beforeMount->mounted 3.父组件: ->mounted->beforeDestroy 4.子组件:->beforeDestroy->Destroyed 5.父组件:->Destroyed 过渡、动画: 当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理: 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)
可复用性、组合
混入:混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
自定义指令
Vue.directive('focus', { inserted: function(el){ el.focus() } }) 钩子函数: bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。 unbind:只调用一次,指令与元素解绑时调用。
Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '
' + 'value: ' + s(binding.value) + '
' + 'expression: ' + s(binding.expression) + '
' + 'argument: ' + s(binding.arg) + '
' + 'modifiers: ' + s(binding.modifiers) + '
' + 'vnode keys: ' + Object.keys(vnode).join(', ') } })
new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } }) 过滤器 {{ message | capitalize }}
filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } }
Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) })
new Vue({ // ... })
Vue源码
两个核心API:h.js, patch(app, vnode)
虚拟DOM和diff算法
vdom:虚拟dom,用JS模拟DOM,因为DOM操作昂贵,将DOM对比操作放在JS层,提高效率 diff:linux的基础命令,vdom中使用时为了更快找出需更新的节点。 实现:patch(container, vnode) patch(vnode, newVnode) 核心逻辑:createElement,updateChildren 解析模板 模板本质是字符串,有逻辑,如v-if,v-for。与html很像,但是有区别,html无逻辑,最终要转换为html来显示 render函数: vm._c其实相当于snaddom中的h函数。render函数执行后,返回vnode。 1)with函数 2)类似vdom的h函数 updateComponent: updateComponent中实现vdom的patch,页面首次渲染执行updateComponent,data中每次修改属性,执行updateComponent。 数据响应式原理: 修改data属性后,vue立刻监听到,data属性被代理到vm上
Vuex
State: state: { count: 0 },
this.$store.state.count
import { mapState } from 'vuex' ...mapState({})
Getter:就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } }
Mutations: Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
mutations: { increment (state) { // 变更状态 state.count++ } }
Actions: Action 类似于 mutation,不同在于: Action 提交的是 mutation,而不是直接变更状态。 Action 可以包含任意异步操作。 actions: { increment (context) { context.commit('increment') } } Modules: Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
Vue-router
基础路由
动态路由匹配 { path: '/user/:id', component: User } this.$route.params 嵌套路由:借助router-view
编程式导航: router.push() router.replace(location,onComplete?,onAbort?)替换掉当前history的记录 router.go(n):在history记录向前或向后几步 命名路由: const router = new VueRouter({ routes: [ { path: '/user/:userId', name: 'user', component: User } ] })
链接到命名路由: User router.push({ name: 'user', params: { userId: 123 }}) 命名视图:
User Settings
{ path: '/settings', // 你也可以在顶级路由配置命名视图
component: UserSettings, children: [{ path: 'emails', component: UserEmailsSubscriptions },
{ path: 'profile', components: { default: UserProfile, helper: UserProfilePreview } }] } 重定向和别名: 1)
重定向:{ path: '/a', redirect: '/b' } 2)别名:/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。 { path: '/a', component: A, alias: '/b' } 路由组件传参:使用props将组件和路由解耦 1)布尔模式:{ path: '/user/:id', component: User, props: true } 2)对象模式:{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } 3)函数模式:{ path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } 路由模式: 1)默认hash模式(带#),使用url的hash来模拟一个完整的url,于是当url改变时,页面不会重新加载。 2)history模式:优美,利用history.pushState API完成URL跳转,而无需重新加载页面:mode: 'history'
进阶路由
导航守卫:
1)全局前置守卫:
router.beforeEach((to, from, next)=>{})
2)全局解析守卫:
router.beforeResolve
3)全局后置钩子:
router.afterEach((to, from)=>{})
4)路由独享的守卫:beforeEnter: (to, from, next)=>{}
5)组件内的守卫:beforeRouterEnter(to,from,next){}, beforeRouteUpdate(to,from,next){}, beforeRouteLeave(to,from,next){} 路由元信息:=:定义路由的时候可以配置meta字段,通过遍历$route.matched来检查路由记录中的meta字段。 过渡动效: 数据获取: 1)导航完成后获取:先完成导航,然后再接下来的组件生命周期苟子仲获取数据。 2)导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据成功后执行。 滚动行为:只有在history模式才能使用。 scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 return { x: 0, y: 0 } } 路由懒加载 const Foo = () => import('./Foo.vue') const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })
axios
特点:
- 1. 从浏览器中创建 XMLHttpRequests
- 2. 从 node.js 创建 http 请求
- 3. 支持 Promise API
- 4. 拦截请求和响应
- 5. 转换请求数据和响应数据
- 6. 取消请求
- 7. 自动转换 JSON 数据
- 8. 客户端支持防御 XSRF 常用方法 axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]]) axios.patch(url[, data[, config]]) 拦截器: // 添加请求拦截器 axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); });
// 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); });
删除拦截器 const myInterceptor = axios.interceptors.request.use(function () {/.../}); axios.interceptors.request.eject(myInterceptor); VUE SSR
Vue3.0
Vite
新特性
组合式API Teleport 触发组件选项createRenderer 单文件组件组合式API 单文件组件状态驱动的CSS变量
变更
Global API模板指令 组件 渲染函数 生命周期 其它 断开与目标 VM 的连接,地址:'javadebug', transport: '共享内存'