🌕写在前面
🍊博客主页 :勇敢link牛牛
🎉欢迎关注:🔎点赞👍收藏⭐️留言📝
🌟本文由 勇敢link牛牛 原创,CSDN首发!
📆首发时间:🌹2022年8月29日🌹
🆕最新更新时间:🎄2022年8月29日🎄
✉️愿你熬过万丈孤独,藏下星辰大海!
📠参考书籍:📚《Vue2》
🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢感谢感谢!
Vue.js是一套构建用户界面的渐进式框架。Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与单文件组件和 Vue 生态系统支持的库结合使用时,Vue 也完全能够为复杂的单页应用程序提供驱动。
- 渐进式:一步一步,不是说你必须一次把所有的东西都用上
- 自底向上设计:是一种设计程序的过程和方法,就是先编写出基础程序段,然后再逐步扩大规模、补充和升级某些功能,实际上是一种自底向上构造程序的过程。

Vue从设计角度来讲,虽然能够涵盖这张图上所有的东西,但是你并不需要一上手就把所有东西全用上,都是可选的。声明式渲染和组件系统是Vue的核心库所包含内容,而路由、状态管理、构建工具都有专门解决方案。这些解决方案相互独立,你可以在核心的基础上任意选用其他的部件,不一定要全部整合在一起。

💖声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统
<div id="app">
{{ message }}
div>
#js
var vm = new Vue({
// 选择真实html中的 选择器
el: '#app',
// 数据源 -- 声明模板变量所在的位置
data(): {
// 返回一个对象
return {
// 声明一下变量
message: 'Hello Vue!'
}
}
})
💖 组件化应用构建
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。几乎任意类型的应用界面都可以抽象为一个组件树。
{
tag:div
children:[
{
tag:div
children:[
…
]
}
]
}

1.3、MVVM模式
MVVM是Model-View-ViewModel的简写。它本质上就是MVP 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
vue使用MVVM响应式编程模型,避免直接操作DOM , 降低DOM操作的复杂性。
优点:
使用js对html页面结构中的指定的区域输出数据
<div>div>
<input type="text" name="" id="">
<script>
var input = document.querySelector("input");
input.addEventListener("input",function(e){
var div = document.querySelector("div");
div.innerHTML = this.value.trim();
});
script>
<body>
<div>div>
<input type="text" name="" id="">
<script>
/* 数据源 */
var data ={
message :"我爱你"
}
var target = {};/* 做个代理中转 目标数据*/
/* 做个属性侦听改变侦听 响应数据*/
Object.defineProperty(target,"message",{
get(){
// return data.message;
return Reflect.get(data,"message")
},
set(newValue){
data.message = newValue;
document.querySelector("div").textContent = newValue;
}
})
/* 初步把数据源的值,分别传给div和input */
var input = document.querySelector("input");
input.value =target.message;
document.querySelector("div").textContent = target.message;
/* 间接代理服务 */
input.addEventListener("input",function(e){
target.message = this.value.trim();
});
script>
body>
在html页面中使用好vue需要完成如下步骤即可
{{变量名}}Vue参数对象属性
插值表达式
将数据填充到HTML标签中
支持基本的JavaScript计算操作,例如算术运算、字符串拼接等
下载vue.js
在html中引入vue.js文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue学习使用title>
<script src="./js/vue.js">script>
head>
<body>
<div id="app">
<h3>{{ title }}h3>
<input type="text" v-model="title">
div>
<script>
const vm = new Vue({
// vue处理完成数据展示在页面中的挂载点dom
el: '#app',
// vue2中,唯一一个地方可以把data写成对象地方,就是在实例化vue类时
// 声明vue要渲染的数据
data: {
title: 'hello vue'
}
})
console.log(vm.title)
// document.getElementById('setTitle').value = vm.$data.title
// document.getElementById('setTitle').oninput = e => vm.$data.title = e.target.value.trim()
script>
body>
html>
<div id="app">
<div class="div1">{{message}}div>
<input type="text" v-model="message">
div>
<script>
var vm = new Vue({
el:"#app",
data:()=>{
return{
message:"我爱你"
}
}
})
script>

用传统的开发模式,原生JS或JQ操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,因此会马上执行流程,最终执行10次。
例如,第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,前一次计算为无用功。计算DOM节点坐标值等都是白白浪费的性能。即使计算机硬件一直在迭代更新,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户体验。
Web界面由DOM树(树的意思是数据结构)来构建,当其中一部分发生变化时,其实就是对应某个DOM节点发生了变化,虚拟DOM就是为了解决浏览器性能问题而被设计出来的。之前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象操作虚拟DOM节点的好处:页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制,从而提高性能。
通过chrome中的谷歌插件商店安装Vue Devtools工具,此工具帮助我们进行vue数据调试所用,一定要安装。
https://chrome.google.com/webstore?utm_source=chrome-ntp-icon
https://chrome.zzzmh.cn/
在vscode中安装插件

当把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,使用Object.defineProperty(vue2.x),vue3.x中使用了Proxy类把这些属性全部转为getter/setter(数据劫持)。在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

模拟vue实现数据响应式
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="root">
<h3 v-text="title">h3>
<hr>
<input type="text" v-model='title'>
div>
<script>
// 数据劫持
let data = {
title: '我是一个标题',
};
// 观察数据
observe(data)
// 给input绑定事件
document.querySelector('[v-model]').addEventListener('input', function () {
let key = this.getAttribute('v-model')
data[key] = this.value.trim()
})
function observe(target) {
if (!isObject(target)) return;
for (let key in target) {
defineReactive(target, key, target[key])
}
}
// 数据劫持
function defineReactive(target, key, value) {
Object.defineProperty(target, key, {
get() {
console.log('get')
return value
},
set(v) {
if (v != value) {
value = v
console.log('set')
// 更新视图
updateView(value, key)
}
}
})
}
function updateView(value, key) {
document.querySelectorAll('[v-text]').forEach(node => {
let attrValue = node.getAttribute('v-text')
if (key === attrValue) {
if (node.nodeName === 'INPUT') {
node.value = value;
} else {
node.innerHTML = value;
}
}
})
}
function isObject(target) {
return {}.toString.call(target) === '[object Object]'
return {}.toString.call(target) === '[object Array]'
}
script>
body>
html>
Vue中当数据发生改变的时候,对应监听的set方法会执行,调用数据中的Dep.notify方法通知所有的订阅者,订阅者就会通过patch函数对比新旧虚拟节点是否一样,如果用新的虚拟节点则整个替换老节点,如果不是使用新节点,则根据子节点情况来进行同层比较。

patch主要做4个判断
①、没有新节点,直接触发旧节点的destory钩子,进行销毁。
②、没有旧节点,此时根本不需要比较了,直接全部都是新建
③、旧节点和新节点一样时,直接调用 patchVnode 去处理这两个节点
④、旧节点和新节点自身不一样,当两个节点不一样的时候,直接创建新节点,删除旧节点

没有key的比较

比对时有key值标识

key值的作用:在使用diff算法比较新旧dom树的时候,可以更准确更快得找到oldDom树中对应的节点。(利用key的唯一性生成map对象来获取对应节点,比遍历方式更快)
patchVnode的位置

插值表达式是vue框架提供的一种在html模板中绑定数据的方式,使用{{变量名}}方式绑定Vue实例中data中的数据变量。会将绑定的数据实时的显示出来。
{{变量、js表达式、三目运算符、方法调用等}}
<div id="app">
vue模板的表达式为 {{ 变量 }}
表达式中不能定义变量或函数,也不可以写if条件或循环
<div>{{ title }}div>
进行计算 vue模板中不太建议在里面写运算
<div>{{ 1+1 }}div>
调用函数或方法
<div>{{sum()}}div>
调用js内置方法 不太推荐
<div>{{ '电饭锅是'.substr(0,3) }}div>
三目运算
<div>{{ age<20?'未成年':'成年' }}div>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
age: 18,
title: 'hello vue',
函数可以写在data中的,但是不太建议
data中的数据都会被劫持,但是函数是没有必须劫持的
vue为了提升性能,新增一个配置选项,用于定义函数方法method,它不会被劫持
},
methods: {
sum() {
return 1 + 2
}
}
})
script>
注:{{}}括起来的区域,就是一个就是js语法区域,在里面可以写部份的js语法。不能写 var a = 10; 分支语句 循环语句
指令(Directives)就是vue给html标签提供的一些自定义属性,这样属性都是带有 v- 前缀的特殊属性。指令特性的值预期是单个JS表达式(v-for是例外情况)。
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM。
vue中的指令可以操作真实的dom的
指令作用:
v-html :解析html指令 注:尽量避免使用,容易造成危险 (XSS跨站脚本攻击)
v-text :输出文本信息二者都有消除闪白、闪动的能力
题
<div id="app">
<h3>{{html}}h3>
<div v-html="html">div>
<div v-text="html">div>
div>
<script src="./vue.js">script>
<script>
new Vue({
el: '#app',
data: {
html:'百度一下'
}
})
script>
指令扩展了html标签的功能、大部分的指令的值是js的表达式,取代了DOM操作。
解决浏览器在加载页面时因存在时间差而产生的“闪动”问题
v-html或v-text它们能够解决闪现,但是有的时候,一些项目在前期没有用它,这时候如果全部去修改,工程量有点大,可以用此指令
# css中设置
[v-cloak] {
display: none;
}
# html
<div v-cloak>
{{ message }}
div>
此指令一个性能优化的指令,使用它,可以提升性能。
跳过这个元素和它的子元素的编译过程,跳过大量没有指令的节点会加快编译。
<span v-pre>不需要编译,直接可以运行span>
ul中的数据,它是一个固定的,没有通过vue中的数据来渲染
无需把它们转为虚拟dom,直接存储html,在显示直接输出
<ul v-pre>
<li>首页li>
<li>列表li>
ul>
只渲染元素和组件一次,之后元素和组件将失去响应式功能
对于某些特定数据,只绑定一次 性能优化
<div id="app">
<h3>{{message}}h3>
<hr>
<div v-once>{{message}}div>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
message: '你好世界'
}
})
script>
根据表达式的布尔值(true/false)进行判断是否渲染该元素
v-if是对dom元素的移除和创建
v-show是通过修改标签的display值
v-if:如果条件不成立,则不创建或删除已创建元素,初始化它的性能更高一些,如果频繁切换则性能低一些,权限显示相关,建议用v-if
v-show:如果条件不成立,通过样式来隐藏,初始化它的性能低一些,如果频繁切换则性能更好一些
<div id="app">
<p v-if="isShow">我是p标签中的内容p>
<p v-show="isShow">我是p标签中的内容p>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: true
}
})
script>
注:v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-if … v-else-if v-else
必须连在一起使用。
<div id="app">
<div v-if="age<10">儿童div>
<div v-else-if="age<20">少年div>
<div v-else>老年div>
div>
动态地绑定一个或多个属性
<a v-bind:href='url'>跳转a>
<a :href='url'>跳转a>
根据一组数组或对象的选项列表进行渲染。
v-for指令需要使用 (item,index) in 数组或对象 形式的特殊语法,同时还需要指定key值,key的作用在vue进行新旧数据比对渲染页面里,如果有key值会提升比对性能,加快渲染,key使用唯一的值来赋值。
<div id="app">
<ul>
<li v-for="u in users" :key="u">{{ u }}li>
ul>
<hr>
<ul>
<li v-for="(item,key,index) in obj">{{ index }} -{{ key }} - {{item}}li>
ul>
div>
<script src="./vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
users: [1, 2, 3],
obj: {
username: 'zhangsan',
age: 28,
gender: 'male'
}
}
})
script>
绑定事件监听器(事件绑定)
<button v-on:click="事件实现方法()">button>
<button @click="事件实现方法()">button>
# 绑定好事件实现方法后需要在Vue对象中的methods对象中实现对应的绑定方法
methods: {
functionName(arg1,arg2,arg3,...){
// something to do
},
....
}
事件处理函数传参 -- 事件对象--- event对象
<button @click="say">button>
<button @click="say($event)">button>
# 注:如果没有参数时,可以不写小括号,默认就会把event事件对象绑定到实现的方法中,如果需要传参数时,则通过 $event 来手动传递到实现的方法中
事件修饰符
用来处理事件的特定行为
<button @click.stop="doThis">button>
<a @click.prevent="doThis">a>
<div @click.once="incr()">自增一下div>
<ul @click.self="incr()">
<li>你好世界li>
ul>
<button @click.stop.prevent="doThis">button>
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。
<input @keyup.enter="submit">
<div @click.ctrl="doSomething">Do somethingdiv>
你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes = {f2:113}
<input @keyup.f2="add()" value="aaaa">
transition过渡属性对于页面元素的显隐并没有提供过渡方法!这就导致元素从display:none到display:block的过程中,瞬发没有过渡效果。这里我们可以换个思路,用透明度解决这个问题,通过透明度opacity属性从0到1的变化模拟元素的显隐,并且过渡属性transition是提供对透明度opacity属性的过渡的。
暂时没实现过渡效果。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>切换1title>
<script src="./vue.js">script>
<style>
*{
padding: 0;
margin: 0;
}
.div0{
position: relative;
height: 225px;
padding: 0;
margin: 0 auto;
border: 1px solid rebeccapurple;
}
div{
width: 200px;
height: 200px;
}
.div1{
float: left;
position: absolute;
background-color: rgb(239, 85, 85);
transition:all 1s;
Opacity:1;
}
.div2{
float: left;
position: absolute;
background-color: rgb(89, 74, 110);
transition:display 2s;
}
.div3{
float: left;
position: absolute;
background-color: rgb(93, 36, 36);
/* transition:Opacity 2s; */
}
style>
head>
<body>
<div id="app" class="div0">
<button @click="isShow($event)" id="Bn1">1号button><button @click="isShow($event)" id="Bn2">2号button><button @click="isShow($event)" id="Bn3">3号button>
<div class="div1" v-show="buttName =='Bn1'">{{message.substr(0,1)}}div>
<div class="div2" v-show="buttName =='Bn2'">{{message.substr(1,1)}}div>
<div class="div3" v-show="buttName =='Bn3'">{{message.substr(2,3)}}div>
div>
<script>
var vm = new Vue({
el:"#app",
data:function(){
return {
message:"我爱你",
buttName:"Bn1"
}
},
methods:{
isShow(e){
console.log(e.target.id);
this.buttName = e.target.id
console.log(e.target);
}
}
})
script>
body>
html>