网站首页 > 教程分享 正文
首先大家都知道vue是一个MVVM 渐进式框架,MVVM是vue的设计模式,在vue框架中数据驱动视图。
1 MVVM设计模式
View是视图DOM;对应视图也就是HTML部分--代表UI组件,它负责将数据模型转化成UI展现出来。 Model是模型,就是vue组件里的data,或者说是vuex里的数据;--代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。 ViewModel--监听模型数据也就是data的的改变和控制视图行为、处理用户交互,就是一个同步Model以及View的对象,连接它们。
View和Model之间并没有直接的联系,而是通过ViewMode进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。
2 响应式
响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty中的访问器属性中的 get和 set方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上
来看看vue如何监听data变化的
//触发更新视图
function updateView() {
console.log('视图更新')
}
//重新定义数组原型
const oldArrayProperty = Array.prototypo
//创建新对象,原型指向oldArrayProperty,在拓展新的方法(这样不会影响原型)
let arrayProto = Array.prototype
let methods = ['pop', 'shift', 'unshift', 'sort', 'reverse', 'splice', 'push']
methods.forEach(methodName => {
arrayProto[methodName] = function () {
updateView ()
oldArrayProperty[methodName].call(this,...arguments)
}
})
//监听对象属性
function observer(target){
if(typeof target !=='object' || target === null) {
//不是对象或者数组
return target
}
//重新定义数组原型
if (Array.isArray(target)) {
target.__proto__ = arrProto
}
//重新定义各个属性(for in 对象/数组都可以遍历)
for(let key in target) {
defineReactive(target,key,target[key])
}
}
//重新定义属性,监听起来
function defineReactive (target, key, value){
//递归深度监听
observer(value)
//核心API
Object.defineProperty(target,key,{
get(){
return value
},
set(newValue){
if(newValue !== value) {
// 深度监听
observer(newValue)
//设置新值
value = newvalue
//触发更新视图
updateView()
}
}
})
}
// 准备数据
const data = {
name: 'zhangsan',
age: 20,
info: {
address: '北京' // 需要深度监听
},
nums: [10, 20, 30]
}
data.name = 'lisi' //视图更新
data.age = 21 //视图更新
console.log('age', data.age) //age 21
data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
delete data.name // 删除属性,监听不到 —— 所以有 Vue.dete
data.info.address = '武汉' // 深度监听
data.nums.push(4) // 视图更新
检测data变化的APIObject.defindeProperty
const data = {};
let name = "张三毛";
Object.defineProperty(data,'name',{
get:function(){
console.log('触发get')
return name
},
set:function(newVal){
console.log('触发set')
name=newVal
}
})
console.log(data.name) // 触发get 张三毛
data.name = '王麻子' // 触发set
实现数据的获取和赋值的监听
这样就实现数据的获取和赋值的监听了
3 渲染过程
3-1 第一次渲染
- 解析模板为render函数(一般在开发环境已经完成,vue-loader)4
- 触发响应式,监听data属性gettersetter(模板中使用到的变量会触发getter)
- 执行render函数(触发getter),生成vnode,patch(elem,vnode)渲染到页面上
3-1 更新过程
- 修改data的数据,触发setter(此前data数据在getter中已被监听)
- 重新执行render函数,生成newVnode(新的虚拟dom)
- 使用 patch(vnode,newVnode)更新到页面上
- 1、编译模板生成render函数,生成vdom
- 2、执行render函数,触发data中的getter
- 3、getter方法收集依赖(通俗点就是,在模板里面触发了哪个变量的getter,就把哪个变量观察起来)
- 4、在依赖中setter修改data中的数据的时候,Notify看下修改的那个数据是不是之前被观察起来的
- 5、如果是之前观察起来的,就重新渲染( re-render),重新生成render函数,生成newVdom形成一个闭环
4 路由
分为hash以及 history
- protocol - 协议
- hostname - 主机名
- port - 端口
- pathname - url 路径
- search - ?号之后的参数
- hash - #号之后的部分
4-1 hash
- hash 变化会触发页面跳转,即浏览器的前进,后退,hash 永远不会提交到server 端
- hash 变化不会刷新页面,SPA(单页面)必须的特点
- vue中就是通过hash 的变化触发路由的变化,来触发视图的渲染
<body>
<p>
hash路由
</p>
<button id='btn'>
修改 hash
</button>
</body>
<script>
//hash 变化 包括;
//a. js 修改URL
//b. 手动修改url的hash
//c.浏览器的前进、后退
//页面初次加载获取hash
window.addEventListener ('DOMCintentLoaded',() =>{
console.log('hash',location.hash)
})
//hash变化触发
window.onhashchange = (event) =>{
console.log('hash',location.hash)
}
//js 修改 url
document.getElementById('btn').addEventListener('click',()=>{
location.href = '#/user'
})
</script>
4-2 history
h5 history 主要是通过 history.pushState 跳转 和 window.onpopstate 监听页面的前进和后退
<body>
<p>
historyh路由
</p>
<button id='btn'>
修改 url
</button>
</body>
<script>
//页面初次加载获取hash
window.addEventListener ('DOMCintentLoaded',() =>{
console.log('load',location.pathname)
})
//js 修改 url
document.getElementById('btn').addEventListener('click',()=>{
//pushState 有三个参数
//第一个参数是个js对象,可以放任何的内容,可以在onpostate事件中(后面介绍)获取到便于做相应的、处理。
//第二个参数是页面标题:目前所有浏览器都不支持,填空字符串即可
//第三个参数是个字符串,就是保存到history中的url。
let state= {
title:'新页面'
}
history.pushState(state,'','user')
})
//监听浏览器的前进、后退
window.onpostate = (event) => {
console.log(event.state) // {title:'新页面'}
console.log(location.pathname)
}
</script>
history 模式需要后端配合,就是无论用户访问什么路由,所有路由的切换都由前端来做,后端只需要返回index.html的文件,如果后面没有配置兼容,当访问user点击刷新,就会报错user页面NotFoud
互相学习,一起成长,分享更多技术文章!
- 上一篇: JavaScript禁止页面返回(js禁止浏览器后退)
- 下一篇: 前端开发:带你深入理解路由两种模式
猜你喜欢
- 2024-10-28 一起学Vue:路由(vue-router)(vue路由两种方式)
- 2024-10-28 Vue实战065:ScrollBehavior实现路由记录滚动行为
- 2024-10-28 前端开发:带你深入理解路由两种模式
- 2024-10-28 JavaScript禁止页面返回(js禁止浏览器后退)
- 2024-10-28 深度:从零编写一个微前端框架(前端框架从入门到微前端)
- 2024-10-28 2024——前端react进阶题(前端react必读书籍推荐)
- 2024-10-28 浅谈前端路由hash模式和history模式的区别
- 2024-10-28 vue3使用vue-router路由(路由懒加载、路由传参)
- 2024-10-28 手写vue路由(vue路由使用步骤)
- 2024-10-28 前端路由简介以及vue-router实现原理
你 发表评论:
欢迎- 最近发表
-
- 有了这份900多页的Android面试指南,你离大厂Offer还远吗?
- K2 Blackpearl 流程平台总体功能介绍:常规流程功能
- 零基础安卓开发起步(一)(安卓开发入门视频)
- 教程:让你的安卓像Windows一样实现程序窗口化运行
- Android事件总线还能怎么玩?(事件总线有什么好处)
- Android 面试被问“谈谈架构”,到底要怎样回答才好?
- Android开发工具Parcel和Serialize
- Android 中Notification的运用(notification widget安卓)
- Android退出所有Activity最优雅的方式
- MT管理器-简单实战-去除启动页(mt管理器怎么去除软件弹窗)
- 标签列表
-
- css导航条 (66)
- sqlinsert (63)
- js提交表单 (60)
- param (62)
- parentelement (65)
- jquery分享 (62)
- check约束 (64)
- curl_init (68)
- sql if语句 (69)
- import (66)
- chmod文件夹 (71)
- clearinterval (71)
- pythonrange (62)
- 数组长度 (61)
- javafx (59)
- 全局消息钩子 (64)
- sort排序 (62)
- jdbc (69)
- php网页源码 (59)
- assert h (69)
- httpclientjar (60)
- postgresql conf (59)
- winform开发 (59)
- mysql数字类型 (71)
- drawimage (61)
本文暂时没有评论,来添加一个吧(●'◡'●)