Vue是一套用于动态构建用户界面的渐进式 JavaScript 框架
一,Vue特点
- 采用组件化模式,提高代码复用率,且让代码更好维护
- 声明式编码,让编码人员无需直接操作
DOM,提高开发效率 - 使用虚拟
DOM+优秀的Diff算法,尽量复用DOM节点
2,搭建开发环境
在js里面关Vue生产提示
<script type="text/javascript">
Vue.config.productionTip = false; //阻止vue生成生产提示
</script>
3,使用Vue
- 想让
vue工作,必须创建一个vue实例,且要传入一个配置对象 - root容器里面的代码被称为【
Vue模板】 Vue里面实例和容器是一一对应的- {{
xxx}}中要写js表达式,且可以自动读取到date里面的的所有属性 - 一旦
data里面的数据发生改变,那么页面中用到该数据地方也会发生改变
二,Vue模板语法
1,插值语法
用于解析标签体内容
语法: 语法: {{xxx}} ,xxxx会作为 js 表达式解析
<h1>hello {{name}}</h1>
2,指令语法
- 功能: 解析标签属性、解析标签体内容、绑定事件
- 举例:
v-bind:href = 'xxxx',xxxx会作为js表达式被解析 - 说明:
Vue中有有很多的指令,此处只是用v-bind举个例子
<a v-bind:href="url">11</a>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止vue生成生产提示
const x = new Vue({
el:'#root', //用于指定vue实例为哪个容器服务,值通常为css字符串,
data:{
name:'你好',
url:'www.baidu.com'
}
})
</script>
三,数据绑定
1,单向数据绑定
语法:v-bind:href ="xxx" 或简写为 :href
特点:数据只能从 data 流向页面
2,双向数据绑定
语法:v-mode:value="xxx" 或简写为 v-model="xxx"
特点:数据不仅能从 data 流向页面,还能从页面流向data
注意:使用v-model不能绑定props传递过来的数据,因为props是不可以修改的
el和data的俩种写法
第一种写法
<script type="text/javascript">
Vue.config.productionTip = false; //阻止vue生成生产提示
const x = new Vue({
el: '#root', //用于指定vue实例为哪个容器服务,值通常为css字符串,
data: {
name:'你好',
url:'www.baidu.com'
}
})
</script>
第二种写法
<script type="text/javascript">
Vue.config.productionTip = false; //阻止vue生成生产提示
const v = new Vue({
data(){
return{
name:'你好',
url:'www.baidu.com'
}
}
})
v.$mount('#root');
</script>
四,MVVM模型
M: 模型(Model) :对应 data 中的数据V:视图(View) :模板VM:视图模型(ViewModel):Vue实例对象
观察发现
data中所有属性,最后都出现在了vm身上
vm身上所有属性及Vue原型上的所有属性,在Vue模板上都可以直接使用
五,数据代理
Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2,Vue中数据代理的好处
更加方便的操作data中的数据
3,基本原理
通过Object.defineProperty()把data对象中所有的属性添加到wm上,
为每一个添加到vm上的属性,都指定一个getter/setter,
在getter/setter内部去操作(读/写)data中对应的属性。
通过一个对象代理对另一个对象中属性的操作(读/写)
<script type="text/javascript">
let obj = {x:100}
let obj2 = {y:200}
// 通过obj可以访问和修改obj2的y属性
Object.defineProperty(obj,'y',{
get(){
return obj2.y
},
set(value){
return obj2.y = value
}
})
</script>
六,事件处理
1,绑定监听
v-on:xxx="fun"@xxx="fun"@xxx="fun(参数)"- 默认事件形参:
event - 隐含属性对象:
$event
注意:methods里面函数不要用箭头函数!否则this就不是指向vm了
2,事件修饰符
Vue中的事件修饰符
-
prevent:阻止默认行为
//第一种方法:事件加prevent属性 <a href="http://www.bilibili.com" target="_blank" @click.prevent="pre"> // 第二种方法:方法里面使用 e.preventDefault() <a href="http://www.bilibili.com" target="_blank" @click="pre"> 提示 </a> <script type="text/javascript"> Vue.config.productionTip= false; new Vue({ el:'#root', methods:{ pre(e){ e.preventDefault() alert('你好') }, } }) </script> -
stop:阻止事件冒泡
//第一种方法:事件加stop属性 <div class="demo1" @click="pre"> <button @click.stop="pre">点我</button> </div> // 第二种方法:方法里面使用 e.preventDefault() <div class="demo1" @click="pre"> <button @click="pre">点我</button> </div> <script type="text/javascript"> Vue.config.productionTip= false; new Vue({ el:'#root', methods:{ pre(e){ e.stopPropagation() alert('你好') }, } }) </script> -
once:事件只触发一次
<button @click.once="getNum">触发一次</button> -
capture:使用事件的捕获模式
// 在外层加capture属性 <div class="box1" @click.capture="premsg(1)"> div1 <div class="box2" @click="premsg(2)"> div2 </div> </div> <script type="text/javascript"> Vue.config.productionTip= false; new Vue({ el:'#root', methods:{ premsg(msg){ console.log(msg); } } }) </script> -
self:只有
even.target是当前操作的元素才触发事件 -
passive:事件的默认行为立即执行,无需等待回调函数执行完毕
注意:修饰符可以连续写
// 先阻止默认行为,再阻止冒泡
<a href="http://www.bilibili.com" target="_blank" @click.prevent.stop="pre">
七,键盘事件
1,Vue常用的按键别名
-
回车=>
enter -
删除=>
delete(捕获"删除"和"退格"键) -
退出=>
esc -
空格=>
space -
换行=>
tab(特殊,必须配合keydown去使用) -
上=>
up -
下=>
down -
左=>
left -
右=>`right=// 按下回车键输出内容
<input type="text" placeholder="按下输出文字" @keyup.enter="keyup">
2,系统修饰键
ctrl,alt,shift,meta
配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
// 必须有其他键同时使用才能触发
<input type="text" placeholder="按下输出文字" @keyup.ctrl.enter="keyup">
配合keydown使用:正常触发事件
<input type="text" placeholder="按下输出文字" @keydown.ctrl="keyup">
3,自定义键名
// 语法
Vue.config.keyCodes.自定义键名 = 键码
Vue.config.keyCodes.a =65
注意:e.target.value是输出·当前输入的值
八,计算属性
使用插值语法放在标签里,{{fullname}}
1,定义:要用的属性不存在,要通过已有的属性计算得来
2,原理:底层借助了Object.defineproperty方法提供的getter和setter
3,get函数什么时候执行?
(1),初次读取时会执行一次。
(2),当依赖的数据发生改变时会被再次调用
4,备注:
1,计算属性最终会出现在vm上,直接读取使用即可
2,如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
5,优势
与mothods实现相比,内部有缓存机制(复用),效率更高,调试方便。
computed:{
fullname:{
get(){
console.log('get被调用了');
return this.name.firstname+'-'+this.name.lastname
},
set(value){
let arr = value.split('-');
this.name.firstname=arr[0];
this.name.lastname= arr[1];
}
}
}
简写:
computed:{
fullname(){
return this.name.firstname+'-'+this.name.lastname;
}
}
九,监视属性
当被监视属性变化时,回调函数自动调用,进行相关操作
监视的属性必须存在,才能进行监视!
监视属性的俩种写法
1,new Vue()时,传入watch配置
watch: {
// isFo 为监视的属性
isFo: {
immediate: true, //初始化时让handler调用一下
//handler什么时候调用?当isFo发生改变时
handler(newValue, oldValue) {
console.log('isFo被改变了', newValue, oldValue);
}
}
}
2,通过vm.$watch监视(写在new Vue()外面)
vm.$watch('isFo',{
immediate:true,
handler(newValue,oldValue){
console.log('isFo被修改了',newValue,oldValue);
}
})
3,深度监视
配置deep:true可以监测对象内部值的改变(多层)
<div id="root">
<h2>{{number.a}}</h2>
<button @click="isInfo">点击a+1</button>
<h2>{{number.b}}</h2>
<button @click="isIn">点击b+1</button>
</div>
// js部分
watch:{
number:{
//深度监视
deep:true,
handler(){
console.log('值被改变了');
}
}
}
4,简写形式,只调用handler时可以使用
watch: {
// isFo 为监视的属性
isFo(newValue, oldValue): {
console.log('isFo被改变了', newValue, oldValue);
}
}
十,绑定样式
1,绑定class样式
字符串写法,适用于样式的类名不确定,需要动态指定
<div :class="mood"></div>
data:{
mood:'a',
}
数组写法:适用于要绑定的样式个数不确定,名字也不确定
<div :class="classArr" ></div>
data:{
classArr:['a','b','c'],
}
对象写法:适用于要绑定的样式个数确定,名字也确定,但要动态决定用不用
<div :class="classArr"></div>
data:{
classArr:{
a:true,
b:false,
c:false
}
}
2,绑定style样式
<div :style="[styleObj,styleObj2]" ></div>
data:{
styleObj:{
width:'100px',
height:'200px',
},
styleObj2:{
backgroundColor:'red'
}
}
十一,条件渲染
1,v-if
适用于:切换频率较低的场景
特点:不显示的DOM元素直接被移除
注意:if,else-if中间不能被打断
<!-- v-if做条件渲染 -->
<h2 v-if='n==1'>hello</h2>
<h2 v-else-if="n==2">1</h2>
<h2 v-else>2</h2>
2,v-show
适用于:切换频率较高的场景
特点:不显示的DOM元素未被移除,仅仅使用样式隐藏
备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到
<h2 v-show = 'n==1'>你好1</h2>
注:使用template,不影响结构,只能配合v-if使用
<template v-if="n===1">
<h2>你好</h2>
<h2>你好</h2>
<h2>你好</h2>
</template>
十二,列表渲染
1,v-for遍历数据
<div id="root">
<input type="text" v-model="keyword">
<ul >
<li v-for="(item, index) in arr" :key="item.id">
{{item.id}}-{{item.name}}-{{item.age}}</li>
</ul>
</div>
2,使用watch过滤数据
watch:{
keyword:{
// 必须初始化时让handler调用一下
immediate:true,
handler(newValue){
this.arr = this.student.filter((item)=>{
// console.log(item.name.includes(newValue));
return item.name.includes(newValue)===true
})
}
}
}
3,使用computed过滤数据
computed:{
// arr 必须是没定义的
arr(){
return this.student.filter((item)=>{
return item.name.includes(this.keyword)===true
})
}
}
4,列表排序
computed:{
arr(){
let sortArr = this.student.filter((item)=>{
return item.name.includes(this.keyword)===true
})
if(sortType){
sortArr.sort((a,b)=>{
return sortType===1?a.age-b.age:b.age-a.age
})
}
return sortArr
}
}
5,添加响应式数据
必须是给对象里面添加
// 第一种
Vue.set(vm.student,'age','21')
// 第二种
vm.$set(vm.student,'age','21')
十三,总结数据监测
1,Vue会监视data中所有层次的数据
2,如何监测对象中的数据
通过setter实现监视,且要在new Value时就传入要检测的数据
(1)对象中后追加的属性,Vue默认不做响应式处理
(2)如需给后添加的属性做响应式,使用如下API
Vue.set(vm.student,'age','21') vm.$set(vm.student,'age','21')
3,如何检测数组中的数据
通过包裹数组更新元素的方法实现,本质是做了两件事:
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
4,在Vue中修改数组中的某个元素一定要用以下方法:
push(),pop(),shift(),unshift(),splice(),sort(),reverse()- 使用
Vue.set()或vm.$set(),注意不能给vm的根数据对象添加属性!!!
十四,收集表单数据
1,v-model的三个修饰符
- lazy:失去焦点再收集数据
- number:输入字符串转为有效的数字
- trim:输入首尾空格过滤
<form @submit.prevent="demo">
年龄:<input type="number" v-model.number="user.age"><br>
性别:
男<input type="radio" name="sex" v-model="user.sex" value="male">
女<input type="radio" name="sex" v-model="user.sex" value="femle"><br>
爱好:
学习<input type="checkbox" value="study" v-model="user.hobby">
打游戏<input type="checkbox" value="game" v-model="user.hobby">
运动<input type="checkbox" value="play" v-model="user.hobby"><br>
所属小区
<select v-model="user.city">
<option></option>
<option value="china">中国</option>
<option value="japan">日本</option>
<option value="us">美国</option>
</select>
<button >dianwo</button>
<input type="submit" value="提交">
<!-- <button>提交</button> -->
<input type="checkbox">已阅读并同意<a href="">用户协议</a>、<a href="">隐私政策</a>
</form>
十五,过滤器
- 功能: 对要显示的数据进行特定格式化后再显示
- 注意: 并没有改变原本的数据, 是产生新的对应的数据
语法:
1,注册过滤器:new Vue(flilters:{ })
filters:{
timeFormater(value,str='YY-MM-DD HH:mm:ss'){
return dayjs(value).format(str);
}
}
2,使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”
<h2>现在是{{time|timeFormater}}</h2>
案例:把时间戳转换为特点格式的时间
1,引用第三方关于时间的库
2,使用过滤器
<div id = "root">
<!-- 过滤器实现 -->
<h2>现在是{{time|timeFormater}}</h2>
<!-- 过滤器传参 -->
// time当前时间戳,timeformat为过滤器,必须同时使用
<h2>现在是{{time|timeFormater('YYYY-MM-DD')}}</h2>
</div>
// 局部过滤
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:'#root',
data:{
time:1646709662939
},
filters:{
timeFormater(value,str='YY-MM-DD HH:mm:ss'){
return dayjs(value).format(str);
}
}
})
</script>
// 全局过滤
// 在new Vue实例之前使用,参数为过滤器名
Vue.filter('timeFormater',function(value){
return dayjs(value).format('YY-MM-DD HH:mm:ss');
})
十六,内置指令
1,v-text
写法
<div v-text="name"></div>
相当于
<div>{{name}}</div>
作用:向所在节点中渲染文本内容
与插值语法区别:v-text会替换节点中内容,插值语法不会
2,v-html
写法
<div v-html="str"></div>
data:{
str: '<h3>你好啊</h3>'
}
作用:更新元素的 innerHTML
v-html可以识别html结构
严重注意:v-html有安全问题
- 在网站动态渲染任意
HTML是非常危险的,容易XSS攻击 - 一定在可信的内容上使用
v-html,用不要用在用户提交的内容上
3,v-cloak(没有值)
使用**css配合v-cloak**可以解决网速慢页面展示出 {{xxx}} 的问题
<style>
[v-cloak]{
display:none
}
</style>
<body>
<div id = root>
<h2 v-clock>
</div>
</body>
4,v-once
只执行一次
v-once所在节点在初次动态渲染后,就视为静态内容了
以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
<div id = "root">
<h2 v-once>初始{{n}}</h2>
<h2>当前{{n}}</h2>
<button v-on:click="n++">n+1</button>
</div>
5,v-pre
跳过其所在节点的编译过程。
可利用他跳过:没有使用指令语法、没有使用插值语法的2节点,会加快编译
<h2 v-pre>当前{{n}}</h2>
// 页面显示 当前{{n}}
十七,自定义指令
1,注册全局指令
Vue.directive('max',function(el,binding){
el.innerText = binding.value+100
})
// 使用
<button v-max="n"></button>
2,注册局部指令
new Vue({
directives:{
big(element,binding){
element.innerText = binding.value*10
},
}
})
el:指令所绑定的元素,可以用来直接操作 DOM。
binding:一个对象,包含指令的绑定值等
注:指令如果是多个单词,单词之间用-隔开
十八,生命周期
常用的生命周期钩子
1,mounted:Vue完成模板的解析并把初始的真实的DOM元素放入页面后(挂载完毕)调用;发送ajax请求 ,启动定时器,绑定自定义事件,,订阅消息等【初始化操作】
2,beforeDestory:清除定时器,解绑自定义事件,取消订阅消息等【收尾工作】
十九,组件
1, 模块
理解: 向外提供特定功能的 js程序, 一般就是一个js 文件
为什么: js 文件很多很复杂
作用: 复用js, 简化js 的编写, 提高 js 运行效率
2,组件
理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image…..)
为什么: 一个界面的功能很复杂
作用: 复用编码, 简化项目编码, 提高运行效率
3,模块化
当应用中的js 都以模块来编写的, 那这个应用就是一个模块化的应用。
4,组件化
当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用,。
5,局部组件
// 使用组件
<div id="root">
<school></school><hr>
</div>
<script>
Vue.config.productionTip = false
//定义组件
const school = Vue.extend({
template:`
<div>
<h2>{{age}}</h2>
<span>{{name}}</span>
</div>
`,
data() {
return {
name:'保定学院',
age:12321312312
}
}
})
// 注册组件
new Vue({
el:'#root',
components:{school,home}
})
</script>
6,全局组件
<div id="root">
<home></home>
</div>
<script>
Vue.config.productionTip = false
// 定义组件
const home = Vue.extend({
template:`
<div>
<span>{{nname}}</span>
<span>{{aage}}</span>
</div>
`,
data() {
return {
nname:'家',
aage:12321312312
}
},
})
// 全局注册
Vue.component('home',home)
new Vue({
el:'#root',
components:{school}
})
</script>
注意点:
7,组件的嵌套
<script>
Vue.config.productionTip = false
const school = Vue.extend({
name:'school',
template:`
<div>
<h2>{{age}}</h2>
<span>{{name}}</span>
</div>
`,
data() {
return {
name:'保定学院',
age:12321312312
}
}
})
const home = Vue.extend({
name:'home',
template:`
<div>
<span>{{nname}}</span>
<span>{{aage}}</span>
<school></school> // 必须写
</div>
`,
data() {
return {
nname:'家',
aage:12321312312
}
},
components:{school}
})
new Vue({
el:'#root',
components:{home}
})
</script>
8,VueComponent
1,school组件本质是一个名为VueComponent的构造函数,是Vue.extend生成的
2,我们只需写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(optains)。
3,特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent
4,this执向:
- 组件配置中:
data函数、methods、watch中的函数、computed中的函数,他们的this执向均是【VueComponent实例对象】 new Vue(options)配置中,data函数、methods、watch中的函数、computed中的函数,他们的this执向均是【Vue实例对象】VueComponent的实例对象,以后简称vc(以后也称为组件实例对象),Vue实例对象,以后简称为vmVueComponent.prototype._proto===Vue.prototype- 让组件实例对象(
vc)可以访问到Vue原型上的属性、方法.