VUE学习随笔
做的事儿和二阶段一样,但是语法变化较大,一切的框架都是为了简化DOM操作(语法麻烦、渲染多了影响效率)
VUE一、vue介绍二、vue的使用模板1、vue2.0的模板和class和style操作样式 :2、vue3的模板以及class和style的样式操作:三、vue2,3公共用法1、vue插值表达式:2、vue指令:1.条件渲染v-if、v-else-if、v-else:2.列表渲染v-for:3.事件处理器:4.表单控件:5.自定义指令:3、计算属性:4、监听属性:四、组件化开发1、组件的创建/注册:2、组件通信 :1.父传子:2.子传父:3.中间人模式:4.bus总线:5.refs:6.内置组件:7.组件的生命周期:
一、vue介绍
渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。(难度还好,但是量大) 构建数据驱动的web应用开发框架,属于前端框架。
-
为什么受欢迎? 1、声明式渲染:应对前端后分离开发的大趋势 2、渐进式框架:适应各种业务需求以及场景(vue从小到大都可以胜任) 3、更适合移动端:现在的趋势也是移动端为主,SPA页面(单页面开发 - 效率更高,只有一个.html文件) 4、快速交付:结合一些第三方UI插件库/框架/组件库 - elementUI(PC端)/vantUI(移动端) 5、企业需求:必备技能(vue或react 二选一) 6、中国的框架(作者借鉴了react和angular)
-
vue是一个属于mvvm架构的框架,什么是mvvm? m - model:模型数据 v - view:视图 vm - ViewModel:vm控制器 我们一般统称为mv*架构:mvc、mvp、mvvp
-
学习目的:vue一共学习4周,呆老师教你一周vue基础,vue全家桶由三部分组成: 1、vue 2、vue router - vue路由,做项目的时候才学习 3、vuex - 状态机:在不同的页面,我们需要一个状态,来判断什么操作,比如登录了吗,类似于我们二阶段学习的webStorage
-
开发环境搭建: 1、下载引入vue.js(版本2.0和3.0,我们都学习):
<script src="2.0或3.0"></script>
2、脚手架方式 - 项目开发时才用,深入学习后
二、vue的使用模板
1、vue2.0的模板和class和style操作样式 :
-
模板
顺序无所谓,但是一定要按照这些键值对来玩
new Vue({
el:"#box",//vue确定使用范围,只能在id叫box的元素里,才可以使用vue的语法,控制环境范围
data:{//模型数据:vue专门为你提供了放变量的地方
变量名:值,
...
},
methods:{//事件方法:vue专门为你提供了放事件的地方
函数名(){
功能
},
...
},
})
-
vue2的class和style操作样式 - vue.js在控制样式:
1、class操作样式:- 两种语法糖
<elem :class="obj"></elem> - 对象口味的语法糖,对应下方的模型数据,可知class最终只有aa和bb
<elem :class="arr"></elem> - 数组口味的语法糖,对应下方的模型数据,可知class最终只有aa和bb
new Vue({
el:"#box",
data:{
obj:{ - 对象口味的语法糖
aa:true,
bb:true,
cc:false,
...
}, - 后续不能直接添加dd,vue底层具有拦截机制,想要添加,必须vue提供的方法:Vue.set(Vm对象.obj,"dd",true)
arr:["aa","bb",...] - 可以随时的添加和删除,相比对象口味语法糖更加的随意简单
},
})
2、style内联操作样式:
<elem :style="obj"></elem> - 对象口味的语法糖,对应下方的模型数据,可知现在具有背景颜色为红色
<elem :style="arr"></elem> - 对象口味的语法糖,对应下方的模型数据,可知现在具有背景颜色为红色
new Vue({
el:"#box",
data:{
obj:{ - 对象口味的语法糖
backgroundColor:"red",
...
}, - 后续不能直接添加样式,vue底层具有拦截机制,想要添加,必须vue提供的方法:Vue.set(Vm对象.obj,"样式名","样式值")
arr:[{"backgroundColor":"red"},...]
},
})
2、vue3的模板以及class和style的样式操作:
注意:Vue3除了语法不同,生命周期中的两个销毁也不一样:beforeUnmount、unmounted
1、模板:vue是不需要实例化对象的(不需要new XXX)
直接写为:
var app=Vue.createApp({
//创建变量有所不同,写为函数式创建
data(){
return {
name:"paoge"
}
},
methods:{},
computed:{},
watch:{},
.....
}).mount("#box");//mount - 挂载
app.component("组件名",{ //组件写法与vue2不同
template:``,
})
2、反而vue3操作样式不用担心vue2的问题,之前vue2的对象语法糖的拦截部分,可以忽略不管了额,对象可以直接使用老JS语句添加/删除了
三、vue2,3公共用法
1、vue插值表达式:
-
{{变量}} - 在HTML上实现了一个基本的js环境,可以进行js运算、放入变量、三目、甚至API都可以在HTML上书写
2、vue指令:
-
写在HTML上的v-xxx的特殊属性,就是所谓的指令
vue指令:写在HTML上的v-xxx的特殊属性,就是所谓的指令
v-html - 类似于innerHTML,可以识别渲染标签
语法:<elem v-html="变量"></elem> - 此标签中就会具有变量的值/内容
特殊:不要使用插值表达式渲染页面,插值表达式类似的是innerText不识别标签的,当作原文处理
v-for - 类似for in循环,数据渲染!
语法:<elem v-for="(v,i) in 数组名"></elem> - 会根据数组中的元素渲染出多个此元素elem,可以拥有值和下标(由你自己决定)
v-model - 具有双向数据绑定功能,页面控制变量,变量也能控制页面
语法:<input v-model="变量"> - input的默认值就为变量的值,并且input修改内容,变量也会跟着一起变化(以后可以不用oninput/onblur事件就可以得到用输入的value)
v-show - 隐藏和显示,传入的是一个布尔值,底层原理:display:block/none;
v-if - 是否渲染,,传入的是一个布尔值,底层原理:appendChild/remove;
语法:<elem v-show/if="布尔变量"></elem>//如果布尔值为true则显示,如果为false则隐藏
v-bind:属性名="变量" - 意味着原来JS标准属性里面是不可以放入变量的,但是现在可以了,简写方式 - :class="变量"
v-on:事件名="函数名()" - 绑定事件的,简写方式 - @事件名="函数名()";
1.条件渲染v-if、v-else-if、v-else:
1、订单显示:
<ul>
<li v-for="obj in datalist" :key=obj.id>
{{obj.title}}---
<span v-if="obj.state===1">未付款</span>
<span v-else-if="obj.state===2">待发货</span>
<span v-else-if="obj.state===3">已发货</span>
<span v-else>已签收</span>
</li>
</ul>
通过以上代码,我们可以实现:
1、根据datalist数据渲染出很多个li
2、并且判断datalist里面每个对象的状态,显示出不同的span或不同的文字
并不只有v-if,还有v-else-if、v-else,可以让我们在多个条件中选择其中一个 (隐藏和显示)
2、如果希望多个子元素同时显示|同时隐藏,可以在父元素上设置一个v-if,但是推荐使用template标签,这是一个vue提供的包装元素,并不会真的渲染到DOM树上,不会创建在页面上的
也是我们见过的第一个虚拟DOM节点:<template></template>
2.列表渲染v-for:
1、v-for:可以遍历数组、对象、甚至是一个数字
<ul>
<li v-for="(v,i) in 需要被遍历的数据" :key="不重复的东西">{{v}}</li> - 注意:遍历数字基本没什么意义,不管是遍历对象还是数组,前面始终是值,后面始终是下标
</ul>
2、面试题:为什么v-for过后都要添加一个自定义属性key?
以前二阶段:数据->渲染到DOM数据,(不管是渲染还是删除,只要DOM变化)渲染次数越多,性能就越差
虚拟DOM:数据->vue变为虚拟DOM:js对象描述了一个节点->真实DOM
新的数组会生成新的虚拟DOM,然后vue底层会使用diff算法拿着新生成的虚拟DOM和老的真实DOM进行对比,找不同
找到不同后,会更新出一个补丁,再渲染到真实DOM之中,这样的好处就是性能代价最小
为什么说虚拟DOM代价小呢?因为真实DOM非常的复杂,有很多很多的属性,但是虚拟DOM只需要重要的属性
虚拟DOM中用到的diff算法默认也是比较笨的,会一一的进行对比,效率低下,所以建议添加key属性
理想情况:key="v.id",id是绝对不会重复的
强调/记死:
1、只要用了v-for就要用上:key,为了触发虚拟DOM
2、:key必须写一个不重复的东西,千万别是下标,最好是ID
目的:高效复用DOM
3、数组更新检测:
1、不能监测数组变动的操作
arr[下标]=新值;
vue3不必担心此问题了
2、强烈推荐:都可以监测到数组变动,页面也就会跟着变化
push/pop/shift/unshift/splice/sort/reverse
3、一般般的:
filter/concat/slice/map - 不会修改原数组,只返回新数组,新数组又不会影响到页面,那我们必须用新数组去覆盖原数组才可以改到页面(数据驱动视图)
3.事件处理器:
1、*绑定事件:@事件名="函数名()";
*特殊:
1、函数名的(),如果不传入参数,其实可以省略不写
2、如果调用时,没有加(),我们的methods事件函数甚至会自动获得一个形参 - event对象
3、如果调用时,传入了自己的实参,但又想得到event对象,必须固定写为:
<button @click="f1($event,1,2,3)">按钮</button>
2、事件修饰符:
@事件名.stop="函数名()"; - 阻止冒泡
@事件名.self="函数名()"; - 只有点击自己才触发
@事件名.prevent=函数名()"; - 阻止默认行为
都是在简化event的事情
3、按键修饰符:
@keydown.enter="函数名()" - 只有回车才会触发
@keydown.enter.ctrl="函数名()" - 只有回车和ctrl同时使用才会触发
还有很多:.esc .up .left .right .down .space .shift .delete 甚至可以.键码
4.表单控件:
(写在form元素里面的标签就是表单控件)绑定:v-model - 记住:以后有没有事件我们都可以得到用户输入/选择的东西 - 【双向数据绑定】
1、获取input中用户输入的内容
<input type="text" v-model="变量" /> - 只要用户输入了,变量就会自动变化,自动得到
2、多选框:想要知道被选中没有 (购物车全选)
<input type="checkbox" v-model="布尔变量" />
如果用户操作了页面这个多选框,那么此布尔值就会自动变化,如果用户勾选了,则为true,如果用户没选上,则为false
3、如果有多个多选框:想要知道谁被选中了
<input type="checkbox" v-model="arr" value="苹果" />苹果
<input type="checkbox" v-model="arr" value="香蕉" />香蕉
<input type="checkbox" v-model="arr" value="梨子" />梨子
注意:必须用数组变量,保存input的value值,此数组中有哪些人的value,哪些人就会被勾选中,反之没有
4、单选框:判断选中了谁
<input type="radio" v-model="gender" value="男" />男
<input type="radio" v-model="gender" value="女" />女
根据gender变量中保存的value值,来判断你选中的是谁
强调:单选框和多选框不要用点击事件,时机不对,必须使用change事件
5、表单修饰符:
v-model.lazy="变量"; - lazy懒惰,只会在失去焦点时获取到用户输入的内容
v-model.number="变量"; - 自带隐式转换为数字的操作(以前我们说页面上一切用户输入的数据都是字符串)
v-model.trim="变量"; - 去掉字符串开头结尾的空白字符
5.自定义指令:
为了操作底层dom,作者给我们留的方案,你觉得他提供的指令不够玩了,我们可以自定义指令(自己书写底层javascript原理)
何时:我想要操作dom,作者还没提供
创建指令:
Vue.directive("paoge",{
//指令的生命周期
inserted(el,binding){//第一次会使用指令时会执行
// console.log(el);//当前使用了此指令的元素
// console.log(binding);//对象,binding.value 就可以得到用户传给我们的数据
el.style.background=binding.value
},
update(el,binding){//指令修改后,想要再次执行,需要 写update生命周期
el.style.background=binding.value
}
})
简化:简化后不光具有inserted的功能也具有update的功能
Vue.directive("paoge",()=>{
el.style.background=binding.value
})
注意:
1、vue3的指令的生命周期和vue2并不一样,约等于 组件的生命周期
2、this.$nextTick(()=>{
比生命周期updated执行的还要晚,在此处更适合调用插件初始化(new Swiper)操作
})
3、计算属性:
防止模板过重,【难以维护】,负责逻辑计算的操作全部放到计算属性之中来写
var vm=new Vue({
data:{},//状态、变量、模型数据
methods:{},//方法 - 事件
computed:{//方法 - 计算
函数名(){
return 结果;
特殊:
1、在HTML使用时,函数名不需要();
2、必须添加return进行返回结果
3、和methods很像,但是methods调用了几次就会执行几次,但是computed如果数据不方法变化,他只会做第一次
}
}
})
4、监听属性:
var vm=new Vue({
data:{},//状态、变量、模型数据
methods:{},//方法 - 事件
computed:{},//方法 - 计算
watch:{//方法 - 专为监听input准备的
v-mdel绑定的变量名(newval,oldval){//能够时刻监听到数据的变化,比如:input不再需要绑定oninput和onblur事件
操作
}
}
})
总结:
1、data -> 状态、变量、模型数据
2、methods:事件
3、computed:重视结果,逻辑计算。解决模板过重的问题(以后方便维护),只求结果,必须要有return
4、watch:监听一个值的改变
Vue2也叫做选项式API - 你想要哪部分,需要自己选择
Vue3也叫做组合式API
四、组件化开发
为什么要组件化: 1、扩展HTML元素,封装可以重用的代码 2、单页面开发,其实就是在调用各种各样的组件
1、组件的创建/注册:
1、全局组件/局部组件:
Vue.component("组件名",{ //component组成部分
template:`<div css/js>内容</div>`, - 写HTML模板 //template模板
methods:{}, //方法-用于事件
computed:{}, //计算
watch:{}, //监视
data(){
return {
}
},
components:{//局部组件
"组件名":{
template:`<div css/js>内容</div>`,
...套娃
}
}
})
new Vue({}) 根组件
2、使用组件:<组件名></组件名>
3、注意:
1、起名字:如果js写为驼峰命名,HTML不支持,必须写为连接符-
2、dom片段(template模板),没有代码提示,没有高亮显示 - 下周vue单文件组件才可以解决
3、css只能写成行内样式 - 下周vue单文件组件才可以解决
4、template只能包含一个根节点
5、自定义组件的data都必须是vue3的函数式写法
6、所有的组件都放在一个.js里肯定太乱了, - 下周vue单文件组件才可以解决
7、组件是一座孤岛,无法【直接】访问外面你的组件的状态或方法 - 明天学习的【组件通信交流】
何时使用全局或局部组件:
1、如果一个组件只会使用过一次推荐定义为局部
2、如果一个组件在不同的页面、在不同的各个组件中都会使用到,推荐为全局
2、组件通信 :
组件是一座孤岛,默认无法状态(data)通信,父子关系极差
目的 - 提升组件的复用性
比如:一个网站上的任何一个页面,都有导航条,相似却不相同,我们可以实现一个组件,传入不同的参数实现不同的效果
1.父传子:
自定义属性
<组件名 自定义属性名="根组件的data数据"></组件名>
Vue.component("组件名",{
template:``,
props:["自定义属性名"],
props:{
自定义属性名:{
type:String,
default:默认值,
}
}
})
--------------------------------------------------
详细例子:
//在根组件中的#box里面将自定义属性的值传给全局组件,子组件用props存储。
//props的第一种写法的html
<div id="box">
<navbar myname="首页" :bool="false" :bool1="true"></navbar>
<navbar myname="购物车页" :bool="true" :bool1="true"></navbar>
<navbar myname="产品页" :bool="true" :bool1="false"></navbar>
</div>
//props的第二种写法的html
<div id="box">
<navbar myname="首页" :bool="false"></navbar>
<navbar myname="购物车页"></navbar>
<navbar myname="产品页" :bool1="false"></navbar>
</div>
<script src="./js/vue.js"></script>
<script>
//全局组件
Vue.component("navbar", {
template: `
<div>
<button v-if="bool"><</button>
<span>{{myname}}</span>
<button button v-if="bool1">三</button>
</div>
`,
data() {
return {
}
},
//props的第一种写法::数组语法糖,接收到根组件上传入的自定义属性,我就可以在自己的DOM模板上使用此属性/变量
// props:["myname","bool","bool1"],
//props的第二种写法:对象语法糖,可以限制数据类型&默认值
props: {
myname: {
type: String, //规定了数据类型
default: "导航条" //设置默认值
},
bool: {
type: Boolean,
default: true
},
bool1: {
type: Boolean,
default: true
}
}
})
//根组件