Vue
(一)Vue简介
- Vue是一个JavaScript框架,有其独特的使用规则,按照其规则使用,可以事半功倍
- 它可以大大简化Dom操作
- 具有响应式数据驱动
- 官方文档 官方文档
一.Vue特点
- 采用组件化模式,提高代码复用率、且让代码更好维护(组件.vue==HTML+CSS+JS)
- 声明式编码,让编码人员无需直接操作DOM,提高开发效率
- 使用虚拟DOM+优秀的Diff算法,尽量复用DOM结点
(二)Vue核心基础
一、Vue基础
1.导入(安装)
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
2.el:挂载点
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
var app = new Vue({
data: {
message: 'Hello Vue!'
}
})
app.$mount('#app');
挂载点 :选择HTML元素,Vue会管理该元素及其后代元素(不要挂载和标签)
注意:挂载只能一一对应,不能一对多,也不能多对一
3.data:数据对象
可以嵌套对象,数组等复杂数据,语法与JS语法一致
data:{
massage:'hello!'
}
data(){
return{
massage:'hello!'
}
}
4.MVVM模型
- M:模型(Model):对应data中的数据
- V:视图(View):DOM
- VM:视图模型(ViewModel):Vue实例对象
- data中所有的属性最终都会出现在VM上(数据代理)
5.Object.defineProperty()回顾
let test={
name:'test'
}
let a=18;
Object.defineProperty(test,'age',{
value:18,
enumerable:true,
writable:true,
configurable:true,
get(){
console.log('有人读取了age属性');
return a;
},
set(value){
console.log('有人修改了age属性,且值是'+value);
a=value;
}
})
6.数据代理(重点难点)
数据代理:通过一个对象代理另一个对象中属性的操作(读/写)
- 数据代理的好处:更加方便的操作data中的数据
- 基表原理:
- 通过Object.defineProperty()将data对象中的所有属性添加到VM上
- 为每一个添加到VM上的属性定义一个getter和setter
- 在getter和setter内部去操作(读/写)data中对应属性
二、Vue指令
1.v-text
v-text : 设置标签的文本值(textContent)
<div id="app">
<h1 v-text="massage+'!!!!'"></h1>
<h1 v-text="massage+inf"></h1>
<h1> {{massage}}啊!{{inf}}</h1>
</div>
var app=new Vue({
el:'#app',
data:{
massage:'你好',
inf:'世界'
}
})
2.v-html
v-html : 设置标签的innerHTML
<div id="app">
<h1 v-text="link"></h1>
<h1 v-html="link"></h1>
</div>
var app=new Vue({
el:'#app',
data:{
link:'<a href="https://www.baidu.com">百度</a>'
}
})
注意:v-html存在安全性问题!!!
- 在网站上动态渲染任何HTML是非常危险的,容易导致XSS攻击
- 一定要在可信的内容上使用v-html,一定不能用在用户提交的内容上!
3.v-on
3.1 v-on : 为元素绑定事件
//语法
<div id="app">
<input type="button" value="点我一下" v-on:事件="事件响应函数名">
<input type="button" value="点我一下" @事件="事件响应函数名">
</div>
//实例
<div id="app">
<input type="button" value="点我一下" @click="fun">
</div>
var app=new Vue({
el:'#app',
methods:{
fun:function(){
alert('你好啊!');
}
}
})
3.2 v-on补充:传递自定义参数,事件修饰符
<div id="app">
<input type="button" value="点我一下" @click="fun(name)">
<input type="text" @keyup.enter="fun($event,'李四')">
</div>
var app=new Vue({
el:'#app',
data:{
name:'张三'
},
methods:{
fun:function(event,name){
console.log(event);
alert('你好啊!'+name);
}
}
})
注 :更多详细用法查看文档!官方文档
3.3 Vue中的事件修饰符
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式
- self:只有event.target是当前操作元素时才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
.test5,.test2{
width: 500px;
height: 100px;
padding: 20px;
background-color: skyblue;
}
.test41{
width: 500px;
height: 100px;
background-color: springgreen;
padding: 20px;
}
.test42{
width: 400px;
height: 50px;
background-color: skyblue;
}
.test6{
width: 300px;
height: 100px;
overflow: auto;
}
.test61{
width: 200px;
height: 1000px;
background-color: skyblue;
}
<div id="root">
<a href="https://www.baidu.com" @click.prevent='test1'>百度一下</a>
<div class="test2" @click='test2'>
<button @click.stop='test2'>test2</button>
</div>
<button @click.once='test3'>test3</button>
<div class="test41" @click.capture="test4('test41')">
test41
<div class="test42" @click="test4('test42')">
test42
</div>
</div>
<div class="test5" @click.self='test5'>
<button @click='test5'>test5</button>
</div>
<div class="test6" @wheel.passive="test6">
test6
<div class="test61"></div>
</div>
</div>
var vm=new Vue({
el:'#root',
data:{
},
methods:{
test1(){
alert('就不百度一下!');
},
test2(){
alert('不会冒泡哟!');
},
test3(){
alert('再点一次我就不会弹出来了!');
},
test4(i){
alert(i+'捕获到了点击事件!');
},
test5(e){
alert('你点的是'+e.target);
},
test6(){
for(var i=0;i<10000000;i++){
console.log('test6');
}
}
}
})
注:修饰符可以多个连着使用
3.4 键盘事件
-
Vue常用事件别名
- enter:回车
- delete:删除/退格
- esc:退出
- space:空格
- tab:换行(特殊,必须配合keydown使用,因为tab默认事件是切换焦点)
- up:上
- down:下
- left:左
- right:右
-
Vue未提供别名的按键,可以使用按键原始的Key值去绑定,但是注意如果Key值为两个以上单词,转化为-连接命名(例如:CapsLock:caps-lock)
console.log(event.key,event.keyCode);
-
系统修饰键(用法特殊):ctrl,alt,shift,meta(win键)
- 配合keyup使用:按下修饰键同时,再按下其他键,随后释放其他键,事件才触发。
- 配合keydown使用:正常触发事件
-
可以使用kkeyCode去指定具体按键,但是不推荐!!!
-
Vue.config.keyCodes.自定义键名=键码,可以自定义键名,不推荐!!!
注:键指定可以连着写实现Ctrl+y等事件绑定
4.v-show
v-show : 根据表达式真假,切换元素的显示和隐藏(操作样式:display)
<div id="app">
<img src="" v-show="true">
<img src="" v-show="isShow">
<img src="" v-show="age>=18">
</div>
var app=new Vue({
el:'#app',
data:{
isShow:true,
age:20
}
})
5.v-if/v-else-if/v-else
v-if : 根据表达式真假,切换元素显示和隐藏(操作Dom元素,直接将Dom元素移除或添加)
<div id="app">
<img src="" v-if="true">
<img src="" v-if="isShow">
<img src="" v-if="age>=18">
<div v-if="n===1">a</div>
<div v-else-if="n===2">b</div>
<div v-else-if="n===3">c</div>
<div v-else>d</div>
<div v-if="n===1">a</div>
<div v-if="n===1">b</div>
<div v-if="n===1">c</div>
<div v-if="n===1">
<div>a</div>
<div>b</div>
<div>c</div>
</div>
<template v-if="n===1">
<div>a</div>
<div>b</div>
<div>c</div>
</template>
</div>
var app=new Vue({
el:'#app',
data:{
isShow:true,
age:20,
n:2
}
})
6.v-bind
v-bind : 设置元素属性(如:src,title,class等)
<div id="app">
<img v-bind:src="imgsrc">
<img :alt="ingalt+'!!!'">
<img v-bind:class="isActive?'active':''">
<img v-bind:class="{active:isActive}">
</div>
var app=new Vue({
el:'#app',
data:{
imgsrc:'./01.jpg',
imgalt:'图片1',
isActive:false
}
})
6.1 通过class绑定样式
<div id="root">
<div :class="test1" @click="change1">test1</div>
<div class="basic" :class="test2" @click="change2">test2</div>
<div class="basic" :class="test3" @click="change3">test3</div>
</div>
.class1{
width: 200px;
height: 200px;
background-color: skyblue;
}
.class2{
width: 200px;
height: 400px;
background-color: skyblue;
}
.class3{
width: 400px;
height: 200px;
background-color: skyblue;
}
.class4{
width: 200px;
height: 200px;
background-color: slateblue;
}
.basic{
width: 100px;
height: 100px;
background-color: skyblue;
}
.plus1{
border: black solid 3px;
}
.plus2{
border-radius: 10px;
}
.plus3{
color: blue;
}
var vm=new Vue({
el:'#root',
data:{
test1:'class1',
test2:[],
test3:{
plus1:false,
plus2:false,
plus3:false,
}
},
methods:{
change1(){
var classArr=['class1','class2','class3','class4'];
var index=Math.floor(Math.random()*4);
console.log(index);
this.test1=classArr[index];
},
change2(){
var classArr=['plus1','plus2','plus3'];
if(this.test2.length<3){
this.test2.push(classArr[this.test2.length]);
}else{
for(var i=0;i<3;++i){
this.test2.pop();
}
}
},
change3(){
var a,b,c;
a=Math.floor(Math.random()*2);
b=Math.floor(Math.random()*2);
c=Math.floor(Math.random()*2);
if(a)this.test3.plus1=!this.test3.plus1;
if(b)this.test3.plus2=!this.test3.plus2;
if(c)this.test3.plus3=!this.test3.plus3;
}
}
})
6.2 通过style绑定
<div id="root">
<div class="basic" :style="styleObj">test1</div>
<div class="basic" :style="styleArr">test2</div>
</div>
.basic{
width: 100px;
height: 100px;
background-color: skyblue;
border-radius: ;
}
var vm=new Vue({
el:'#root',
data:{
styleObj:{
fontSize:'30px',
color:'red',
},
styleArr:[
{
fontSize:'30px',
color:'red'
},
{marginTop:'10px'},
{
border:'black solid 2px',
borderRadius:'10%'
}
]
},
})
7.v-for
7.1 v-for : 根据数据生成列表结构
- 可以遍历:数组、对象、字符串(不常用)、指定次数(不常用)
- 用in或者of都行
<div id="root">
<h1>学生列表</h1>
<ul>
<li v-for="(item,index) in students" :key="index">
{{item.id}}:{{item.name}}-{{item.age}}
</li>
</ul>
<h1>学生信息</h1>
<ul>
<li v-for="(value,key) of student" :key="key">
{{key}}:{{value}}
</li>
</ul>
<h1>hello</h1>
<ul>
<li v-for="(char,index) of str" :key="index">
{{index}}:{{char}}
</li>
</ul>
<h1>12345</h1>
<ul>
<li v-for="(v,index) in 5" :key="index">
{{index}}:{{v}}
</li>
</ul>
</div>
var vm=new Vue({
el:'#root',
data:{
students:[
{id:0,name:'张三',age:18},
{id:1,name:'李四',age:20},
{id:2,name:'王五',age:18},
{id:3,name:'赵六',age:19},
],
student:{
id:0,
name:'张三',
age:18
},
str:'hello'
},
})
7.2 v-for中的key属性(重点难点)
面试题:react、vue中key有什么作用?(key的原理是什么?)
要点:就是为了提高效率
- 虚拟DOM中key的作用:key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新的虚拟DOM与旧的虚拟DOM的差异比较(diff算法)
- 比对规则:
- 旧的虚拟DOM中找到了与新的虚拟DOM相同的key:
- 若虚拟DOM中内容没变,直接使用之前的真实DOM!(提高效率)
- 如果虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
- 旧虚拟DOM中未找到与新的虚拟DOM相同的key:
- v-for用索引值(index)作为key可能会引发的问题(不写key,Vue就会默认这样使用):
- 如果对数据进行逆序添加、逆序删除等破环顺序的操作:
- 如果结构中还有输入类DOM:
- 会产生错误DOM更新,效率低,界面还会出错(乱序)
- 开发中如何选择key
- 最好使用每条数据的唯一标识作为key
- 如果不存在对数据进行逆序添加、逆序删除等破环顺序的操作,仅仅用于渲染展示,使用索引(index)也是没有问题的
8.v-model
8.1 v-model : 获取和设置表单元素的值(双向数据绑定)
<div id="app">
<input type="text" v-model:value="massage">
<input type="text" v-model="massage">
<h1>{{massage}}</h1>
</div>
var app=new Vue({
el:'#app',
data:{
massage:'你好!'
}
})
8.2 v-mdel补充
-
如果是文本框,则v-model绑定的是value值,用户输入的就是value -
如果是单选框,责v-model绑定的是value值,必须要给标签配置value -
如果是多选框,则:
- 没有配置value,那么绑定的就是checked(true or false)
- 配置了value
- 如果v-modle的初始值是非数组,那么绑定的就是checked(true or false)
- 如果v-modle的初始值是数组,那么绑定的就是value组成的数组
-
v-model修饰符
- number:输入字符串转化为有效数字
- lazy:失去焦点才收集更新数据
- trim:去掉字符串首尾的空格
-
实例 <div id="root">
<form @submit.prevent="output">
用户名: <input type="text" v-model.trim="userinf.username"> <br><br>
密码: <input type="password" v-model="userinf.password" autocomplete="on"> <br><br>
年龄: <input type="number" v-model.number="userinf.age"> <br><br>
性别:
男<input type="radio" name="gender" value="男" v-model="userinf.gender">
女<input type="radio" name="gender" value="女" v-model="userinf.gender"> <br><br>
班级:
<select v-model="userinf.class">
<option value="">请选择班级</option>
<option value="一班">一班</option>
<option value="二班">二班</option>
<option value="三班">三班</option>
</select> <br><br>
爱好:
学习<input type="checkbox" value="学习" v-model="userinf.hobby">
打游戏<input type="checkbox" value="打游戏" v-model="userinf.hobby">
开车<input type="checkbox" value="开车" v-model="userinf.hobby"> <br><br>
其他信息:<textarea v-model.lazy="userinf.other"></textarea> <br><br>
<input type="checkbox" v-model="userinf.agree">是否同意<a href="#">用户协议</a> <br><br>
<button>提交</button>
</form>
</div>
var vm = new Vue({
el: '#root',
data: {
userinf:{
username:'',
password:'',
age:'',
class:'',
hobby:[],
other:'',
agree:''
}
},
methods: {
output(){
console.log(JSON.stringify(this.userinf));
}
},
})
9.v-cloak
- 没有值
- 是一个特殊的属性,Vue实例创建完毕并接管容器后,会自动删除v-colak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出未被Vue解析的模板页面的问题
<!DOCTYPE html>
<html lang="ch">
<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>Document</title>
<style>
[v-clock]{
display: none;
}
</style>
</head>
<body>
<div id="root">
<h1 v-cloak>{{name}}</h1>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#root',
data: {
name:'Vue'
},
})
</script>
</html>
10.v-once
- v-once所在结点在初次动态渲染后,就会被视为静态内容
- 以后数据改变不会引起v-once所在结点的更新,可以优化性能
<div id="root">
<h1 v-once>初始n: {{n}}</h1>
<h1 >n: {{n}}</h1>
<button @click="n++">n+1</button>
</div>
var vm = new Vue({
el: '#root',
data: {
n:1
},
})
11.v-pre
- Vue会跳过其所在结点的解析过程
- 可以利用它跳过:没有用指令,插值等结点,提高性能
<div id="root">
<h1>欢迎访问该系统!!!!!</h1>
<h1 >n: {{n}}</h1>
<button @click="n++">n+1</button>
</div>
var vm = new Vue({
el: '#root',
data: {
n:1
},
})
三、计算属性(重点难点)
计算属性:根据原有的属性经过加工处理计算出来的属性叫做计算属性(computed)
- 原理:底层借助了Object.defineproperty方法提供的getter和setter
- get什么时候执行
- 初次读取计算属性
- 当计算属性依赖的数据发生改变时会被再次调用
- 优势:与methods实现相比,内部有缓存机制(可复用),效率更高
- 注意:
- 计算属性最终会被处理为vm的一个属性,直接读取使用即可
- 计算属性如果需要被修改,则必须使用setter,setter中对应修改计算属性的依赖数据即可
<div id="root">
性:<input type="text" v-model="firstname"> <br><br>
名:<input type="text" v-model="lastname"> <br><br>
性名: <span>{{name}}</span>
</div>
var vm=new Vue({
el:'#root',
data:{
firstname:'张',
lastname:'三'
},
computed:{
name:{
get(){
return this.firstname+'-'+this.lastname;
},
set(value){
var values=value.split('-');
this.firstname=values[0];
this.lastname=values[1];
}
}
}
})
四、侦听(监视)属性
1.侦听(监视)属性
- 当侦听(监视)属性变化时,handler自动调用,进行相关操作
- 侦听(监视)属性必须存在,才能被侦听(监视)
<div id="root">
<h1>你真是个大{{description}}</h1>
<button @click='change'>点我</button>
</div>
var vm=new Vue({
el:'#root',
data:{
isCool:true
},
methods:{
change(){
this.isCool=!this.isCool;
}
},
computed:{
description(){
return this.isCool? '帅哥':'聪明';
}
},
watch:{
isCool:{
immediate:true,
handler(newvalue,oldvalue){
console.log('isCool被改变了,从'+oldvalue+'改成了'+newvalue);
}
},
}
})
2.深度侦听(监视)
- Vue中的watch默认不侦听(监视)对象内部值的改变(一层)
- 配置项
deep:true 可以侦听(监视)对象内部属性值的改变(多层) - Vue自身是可以侦听(监视)对象内部值改变,但是Vue提供的watch默认不可以
- 使用watch时根据实际使用需求,决定是否采用深度侦听(监视)
3.计算属性(computed)和侦听(监视)属性(watch)的区别
- computed能完成的功能,watch都可以完成。
- watch能完成的功能,computed不一定能成功,例如:watch可以进行异步操作
- 两个都行的用computed更简单
- 注意!!
- 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
- 所有不被Vue管理的函数(定时器回调函数,ajax回调函数,Promise的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象
4.侦听(监视)原理(重点难点)
侦听(监视):包括Vue对于数据改变,动态更新页面中用到该数据的DOM,以及watch中侦听(监视)数据地秤实现(同样的逻辑)
-
Vue会侦听(监视)data中所有层级的数据 -
如何侦听(监视)对象中的数据?
-
通过setter实现侦听(监视),而且要是在创建Vue实例对象时就传入的数据才会被Vue侦听(监视) -
对象中后追加的属性,Vue默认不侦听(监视),进而也不会做出响应式处理 -
如果想让后追加的属性也可以被Vue侦听(监视),并响应式处理,需要使用: Vue.set()
vm.$set()
-
如何侦听(监视)数组中的数据?
-
实例 <div id="root">
<button @click="student.age++">年龄加一岁</button> <br>
<button @click.once="addgender">添加性别属性,默认男</button> <br>
<button @click.once="addaf">在朋友们最前面加一个朋友</button> <br>
<button @click.once="updateff">修改第一个朋友的名字</button> <br>
<button @click.once="addh">添加一个爱好</button> <br>
<button @click.once="updatafh">修改第一个爱好</button> <br>
<h1>姓名 {{student.name}}</h1>
<h2>绰号 {{student.nickname}}</h2>
<h3>年龄 {{student.age}}</h3>
<h3 v-if="student.gender">性别 {{student.gender}}</h3>
<h3>朋友们</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}}--{{f.age}}
</li>
</ul>
<h3>爱好</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
</div>
var vm = new Vue({
el: '#root',
data: {
student: {
name: '张三',
nickname: '法外狂徒',
age: 20,
friends: [
{ name: '罗老师', age: 18 },
{ name: '李四', age: 22 },
],
hobby: ['抽烟', '赌博', '干坏事']
}
},
methods: {
addgender() {
this.$set(this.student, 'gender', '男');
},
addaf() {
this.student.friends.unshift({ name: '王五', age: 40 });
},
updateff() {
this.student.friends[0].name = '王大炮'
},
addh() {
this.student.hobby.push('开车');
},
updatafh() {
this.$set(this.student.hobby, 0, '学习');
}
}
})
五、过滤器
过滤器:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑处理)
- 语法:
- 注册过滤器:Vue.filter(name,callback)(全局过滤器) ,new Vue({filters:{}})(局部过滤器)
- 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”
- 备注:
- 过滤器相对于一个函数,但是使用时不需要调用(即使用())默认会接收需要被过滤的数据作为第一个参数,也可以接收额外的参数
- 多个过滤器可以串联
- 过滤器不会改变原始数据,而是对原始数据进行操作,如何产生新的数据
- 一个中文前端插件库:BootCDN
六、自定义Vue指令
-
定义语法:
-
局部指令 new Vue({
directives:{
指令名:配置对象
bind()
inserted()
update()
}
directives:{
指令名(){}
}
})
-
全局指令 Vue.directive(指令名,配置对象)
Vue.directive(指令名,配置函数)
-
备注
- 指令定义时不加v-,但是使用的时候需要加v-
- 指令名如果是多个单词,使用kebab-case命名方式,不用驼峰命名方式。
七、生命周期(重点难点)
- 生命周期,又叫做生命周期回调函数、生命周期函数、生命周期钩子
- 生命周期是Vue在关键时刻帮我们调用了一些特殊名称的函数
- 生命周期函数名称不可更改,但是函数逻辑是由程序员根据需求编写的
- 生命周期函数中的this指向的是vm或组件实例对象
常用的生命周期钩子:
- mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等(初始化操作)
- beforeDestroy:清除定时器、解除自定义事件绑定、取消订阅消息等(收尾工作)
销毁Vue实例:
- 销毁后借助Vue开发者工具将看不见任何信息
- 销毁后自定义事件会失效,但是Vue的工作成果(最后一次更新后的真实DOM)会保留,原生DOM的事件依然有效
- 一般不会在beforeDestroy钩子中操作Vue实例相关数据,因为即使操了,Vue也不会再进行更新等流程
(三)Vue组件化编程
一、简介
二、基础
1.非单文件组件
1.1 基础使用
-
定义组件
- 使用Vue.extend(options)创建,其中options和创建Vue实例时传入的配置项基基本一样,有如下区别
- el配置项不能使用,因为最终组件都会被一个Vue实例管理,由Vue(大哥)决定他及他的组件(小弟)为哪个容器服务
- data必须用函数形式,因为组件为了被复用,用函数才能避免数据存在引用关系
- 注:组件中用template配置组件结构
-
注册组件
- 局部注册:创建Vue实例时的components配置项
- 全局注册:Vue.component(‘组件名’,组件);
- 组件名不要与HTML标签名冲突
-
使用组件
-
实例 <div id="root">
<h1>root</h1>
<heade></heade>
<hr>
<bodyer></bodyer>
<foote></foote>
</div>
<div id="root1">
<h1>root1</h1>
<foote></foote>
</div>
var heade=Vue.extend({
template:`
<div>
<h1>欢迎访问{{name}}系统!</h1>
</div>
`,
data(){
return {
name:'智慧张三'
}
}
})
var bodyer=Vue.extend({
template:`
<div>
<h1>{{name}}列表</h1>
<ul>
<li v-for="(s,index) in students">
{{s.name}}---{{s.age}}
</li>
</ul>
</div>
`,
data(){
return {
name:'学生',
students:[
{name:'张三',age:18},
{name:'罗老师',age:30},
]
}
}
})
var foote=Vue.extend({
template:`
<div>
<h2>版本号{{num}}!</h2>
</div>
`,
data(){
return {
num:'v1.0.1'
}
}
})
Vue.component('foote',foote)
var vm = new Vue({
el: '#root',
data: {
},
components:{
heade,
bodyer
}
})
new Vue({
el: '#root1',
})
1.2 组件命名等注意事项
1.3 关于VueComponent函数
- 组件本质上是一个名为VueComponent的构造函数,而且不需要由我们定义,是Vue.extend生成的
- 我们在使用组件时,Vue解析到会帮我们创建对应组件的实例对象,即执行
new VueComponent(options); - 每次调用Vue.extend,返回的都是一个全新的VueComponent!!!
- 关于this指向
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this都指向VueComponent实例对象
- new Vue()配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this都指向Vue实例对象
1.4 一个重要的内置关系
VueComponent.prototype.__proto__ === Vue.prototype - 目的:让组件实例对象也可以访问到Vue原型上的属性、方法
2.单文件组件
(四)脚手架(CLI)的使用
一、初始化脚手架
- 脚手架是Vue官方提供的标准化开发工具(开发平台)
- 官方文档
- 安装步骤
npm install -g @vue/cli 全局安装@vue/cli (只需要安装一次)- 在你要创建项目的目录下,使用命令创建项目
vue create xxxx - 启动项目
npm run serve - 备注:
-
如果出现下载缓慢,请配置npm淘宝镜像: npm config set registry https://registry.npm.taobao.org --global npm config set disturl https: //npm.taobao.org/dist --global -
Vue脚手架隐藏了所有的webpack相关的配置,如想要查看具体的wekpack配置,请执行: vue inspect > output.js
二、关于不同版本Vue
- vue.js与vue.runtime.xxx.js的区别:
- vue.js是完整版的vue。包含了核心功能+模板解析器
- vue.runtime.xxx.js是运行版的vue,只包含了核心功能,没有模板解析器。
- 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数将收到的createELement函数去指定具体内容。
三、vue.config.js配置文件
- 使用output.js可以查看到脚手架默认配置。
- 使用vue.config.js可以对脚手架进行个性化定制,详见:脚手架配置
//单文件组件示例
<template>
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
import School from './components/Test1.vue';
import Student from './components/Test2.vue';
export default {
name:'App',
components:{
School,
Student
}
}
</script>
<style>
</style>
四、ref属性
-
用来给元素或者子组件注册引用信息(相当于id) -
应用在html标签上获取真实的DOM元素,应用在组件标签上是组件的实例对象(vc) -
使用方式 <template>
<div>
<h1 ref="h1">你好</h1>
<School ref="sch"></School>
<button ref="but" @click="console">输出refs</button>
<Student></Student>
</div>
</template>
<script>
import School from './components/Test1.vue';
import Student from './components/Test2.vue';
export default {
name:'App',
components:{
School,
Student
},
methods: {
console(){
console.log(this.$refs);
}
},
}
</script>
五、配置项props
功能:让组件接收外部传过来的数据
备注:props是只读的,Vue底层会监视你对props的修改,如果进行了修改,就会发出警告
export default {
name:'Student',
data(){
return {
mas:'你好,我是:'
}
},
props:{
name:{
type:String,
required:true
},
gender:{
type:String,
default:'男'
},
age:{
type:Number,
required:true
}
}
}
六、混合(混入)
功能:把某些组件共用的配置提取出来,成为一个混合对象
使用方式
export const mixin={
data(){
return {
message:'你好啊!!'
}
},
methods: {
nihao(){
alert("Hello!");
}
},
mounted(){
console.log("挂载了组件");
},
}
import {mixin} from './mixin';
mixins:[mixin]
import {mixin} from './mixin';
Vue.mixin(mixin);
七、插件
功能:增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用所需要的数据
export default {
install(Vue){
Vue.prototype.test=()=>{
alert('你好!');
}
}
}
import plugin from './plugins';
Vue.use(plugin);
八、scoped样式
作用:让样式只在局部(当前组件生效)其他地方不生效,这样来避免组件间样式冲突
<style scopes></style>
九、web Storage
- 存储内容大小一般支持5MB左右(不同的浏览器可能不一样)
- 浏览端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制。
- 相关API:
setItem('key','value'); 该方法接收一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则直接更新对应的值getItem('key'); 该方法根据键获取存储中的值,如果没有,返回nullremoveItem('key'); 该方法根据键删除存储中的相应的键值对clear(); 清空存储的信息 - SessionStorage(会话存储)存储的内容会随着浏览器关闭而消失
- LocalStorage(本地存储)存储的内容,需要手动清除才会消失
十、组件自定义事件
-
一种组件间通信方式,子组件===>父组件 -
绑定与触发事件 //父组件中
<School @test="getName"></School>
<School ref="school"></School>
methods: {
getName(name){
console.log(name+'拿到了');
}
},
mounted(){
setTimeout(()=>{
this.$refs.school.$on('test',this.getName);
},3000)
}
this.$emit('test',this.name);
-
解除事件绑定
this.$off('test');
this.$off(['test1','test2']);
this.$off();
-
组件绑定原生DOM事件,需要使用native修饰符
十一、全局事件总线(GlobalEventBus)(重点)
-
一种组件间通信的方式,任意组件间通信(基于组件自定义事件) -
安装全局事件总线:(实际上就是造一个中转的组件实例对象,该VC可以被所有其他组件访问到)
beforeCreate(){
Vue.prototype.$bus=this
}
-
使用事件总线
-
接收数据的组件:给$bus绑定自定义事件,事件的回调在自身 methods:{
test(data){}
}
mounted(){
this.$bus.$on('事件名',this.test);
}
-
发送数据的组件 this.$bus.$emit('事件名',data);
-
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
十二、消息订阅与发布(pubsub)
-
一种组件间的通信方式,适用于任意组件间通信。 -
使用
-
安装第三方库:(这里用的是pubsub-js,也可以用其他的)npm i pubsub-js -
引入:import pubsub from 'pubsub-js' -
接收数据的组件中订阅消息,在自身编写回调函数 methods(){
test(data){}
}
mounted(){
this.pubid=pubsub.subscribe('消息名',this.test);
}
-
提供数据的组件发送消息 pubsub.publish('消息名',data);
-
最好在beforeDestroy钩子中,用pubsub.unsubscribe(this.pubid)去取消消息订阅
十三、$nextTick
this.$nextTick(回调函数) - 作用:在下一次DOM更新结束后执行其回调函数。
- 什么时候用,当改变数据后,要基于更行后的DOM进行某些操作的时候,要在nextTick所指定的回调中执行。
十四、Vue封装的过度与动画
-
在插入、更新或者移除DOM元素时,会在合适的时候给元素添加样式类名 -
v-enter == v-enter-active ==> v-enter-to v-leave == v-leave-active ==> v-leave-to -
使用方法
-
准备好样式:
- v-enter:进入的起点
- v-enter-active:进入的过程中
- v-enter-to:进入的终点
- v-leave:离开的起点
- v-leave-active:离开的过程中
- v-leave-to:离开的终点
-
使用<transition> 包裹要过度的元素,并配置name属性: <transition name="test">
<h1 v-show="isShow">你好啊!</h1>
</transition>
-
备注:如果有多个元素需要动画效果,则需要使用:transition-group ,且每个元素都要指定key 值 实例一: <button @click="change">显示/隐藏</button>
<transition name="test" appear>
<div v-show="isShow" class="a">
<h1>{{mes}}</h1>
</div>
</transition>
<button @click="change">显示/隐藏</button>
.test-enter-active{
animation: test 1s;
}
.test-leave-active{
animation: test 1s reverse;
}
@keyframes test{
from{
transform: translateX(-100%);
}
to{
transform: translateX(0);
}
}
实例二: <transition name="test1" appear>
<div v-show="isShow" class="a">
<h1>{{mes}}</h1>
</div>
</transition>
<button @click="change">显示/隐藏</button>
.test1-enter, .test1-leave-to{
transform: translateX(-100%);
}
.test1-leave, .test1-enter-to{
transform: translateX(0);
}
.test1-leave-active, .test1-enter-active{
transition: 1s linear;
}
实例三: <button @click="change">显示/隐藏</button>
<transition-group name="test2" appear>
<div v-show="isShow" class="a" key="1">
<h1>{{mes}}</h1>
</div>
<div v-show="!isShow" class="a" key="2">
<h1>{{mes}}</h1>
</div>
</transition-group>
.test2-enter, .test2-leave-to{
transform: translateX(-100%);
}
.test2-leave, .test2-enter-to{
transform: translateX(0);
}
.test2-leave-active, .test2-enter-active{
transition: 1s linear;
}
-
动画库推荐:animate.css
- 安装
npm i animate.css - 引入
import 'animate.css'; - 官方文档 animate.css
<button @click="change">显示/隐藏</button>
<transition
appear
name="animate__animated animate__bounce"
enter-active-class="animate__rubberBand"
leave-active-class="animate__backOutDown"
>
<div v-show="isShow" class="a">
<h1>{{mes}}</h1>
</div>
</transition>
```javascript
import 'animate.css';
//记得配置这个methods
change(){
this.isShow=!this.isShow;
}
十五、插槽
(五)Vue使用Ajax
一、axios:功能强大的网络请求库
安装 :npm npm上axios地址,网上找都行,到处都是
1.axios基本使用
<div id="app">
<button @click="get">get</button>
<br>
<button @click="post">post</button>
</div>
var app=new Vue({
el:'#app',
methods:{
get:function(){
axios.get("http://127.0.0.1:3000/get?num=4")
.then(
function(res){
console.log(res);
},function(err){
console.log(err);
}
)
},
post:function(){
axios.post("http://127.0.0.1:3000/post",{num:5})
.then(
function(res){
console.log(res);
},function(err){
console.log(err);
}
)
}
}
})
二、Vue脚手架配置服务器代理
-
方法一
devServer: {
proxy: 'http://localhost:5000'
},
students(){
axios.get("http://localhost:8081/students").then(
(res)=>{
console.log(res.data);
},
(err)=>{
console.log(err.massage);
}
)
}
- 优点:配置简单,请求资源时直接发送给本机服务器(8081)即可。
- 缺点:不能配置多个代理,不能灵活选择是否让代理转发请求
- 工作方式:当请求时,优先访问本机服务器,如果本机服务器没有资源,才会转发请求到对应服务器
-
方法二
devServer: {
proxy: {
'/s': {
target: 'http://localhost:5000',
pathRewrite:{'^/s':''},
ws: true,
changeOrigin: true
},
'/c': {
target: 'http://localhost:5001',
pathRewrite:{'^/c':''},
ws: true,
changeOrigin: true
}
}
}
students(){
axios.get("http://localhost:8081/s/students").then(
(res)=>{
console.log(res.data);
},
(err)=>{
console.log(err.massage);
}
)
},
cars(){
axios.get("http://localhost:8081/c/cars").then(
(res)=>{
console.log(res.data);
},
(err)=>{
console.log(err.massage);
}
)
}
- 优点:可以配置多个代理,且灵活控制
- 配置繁琐,请求时需要加前缀
三、vue-resource插件(了解)
- 安装
npm i vue-resource - 使用
- 引入
import vueResource from 'vue-resource' - 使用
Vue.use(vueResource); - 使用
this.$http.get(...)
(六)Vuex(重点)
一、Vuex简介
二、Vuex搭建
-
安装:npm i vuex -
创建文件:src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
actions:{},
mutations:{},
state:{}
})
-
在main.js中配置store
import store from './store'
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(vuex);
new Vue({
render: h => h(App),
store
}).$mount('#app')
三、基本使用
-
初始化数据state、配置actions,mutations actions:{
fun(context,value){
}
},
mutations:{
FUN(state,value){
}
},
state:{
test:0
}
-
组件中读取数据,发起操作
$store.state.test
$store.dispatch('action中的方法名',data)
$store.commit('mutations中的方法名',data)
1. getters配置项
2.四个map方法
引入import {mapState,mapGetters,mapActions,mapMutations} from 'vuex'
2.1 mapState
-
用于帮助我们映射state中的数据为computed计算属性 computed:{
...mapState({a:'test1',b:'test2',c:'test3'})
...mapState(['test1','test2','test3'])
}
2.2 mapGetters
-
用于帮助我们映射getters中的数据为computed计算属性 computed:{
...mapGetters({a:'test1',b:'test2',c:'test3'})
...mapGetters(['test1','test2','test3'])
}
2.3 mapActions
-
用于帮助我们生成与actions对话的方法 methods:{
...mapActions({a:'test1',b:'test2',c:'test3'})
...mapActions(['test1','test2','test3'])
}
2.4 mapMutations
3.模块化+命名空间
-
目的:让代码更好的维护,让多种数据分类更加明确 -
使用方法
-
创建并暴露模块
export default model1={
namespaced:true,
state:{},
actions:{},
mutations:{},
getters:{}
}
export default model2={
namespaced:true,
state:{},
actions:{},
mutations:{},
getters:{}
}
-
在store模块中引入并使用其他模块
import Vue from 'vue'
import Vuex from 'vuex'
import model1 from './model1'
import model2 from './model2'
Vue.use(Vuex);
export default new Vuex.Store({
modules:{
model1,
model2
}
})
-
读取state中数据的方法(在读取时要以某一种形式指明数据所在的模块)
this.$store.state.model1.test1
...mapState('model1',['test1','test2'])
-
读取getters中数据的方法
this.$store.getters['model2/test1']
...mapGetters('model2',['test1','test2'])
-
调用dispatch与Actions对话的方法
this.$store.dispatch('model1/test1',data)
...mapActions('model1',['test1','test2'])
-
调用commit与Mutations对话的方法
this.$store.commit('model2/test1',data)
...mapMutations('model2',['TEST1','TEST2'])
(七)路由 vue-router(重点)
一、vue-router简介
vue-router是vue的一个插件库,专门用来实现SPA(单页面)应用
1.SPA简介
- 单页面Web应用(Single page web application,SPA)
- 整个应用只有一个完整的页面
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
- 数据通过Ajax请求获取
2.路由
- 什么是路由
- 一个路由就是一组映射关系(key-value)
- key是路径,value可能是function或component
- 路由分类
- 后端路由
- 理解:value是function,用于处理客户端提交的请求
- 工作过程:服务器收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据
- 前端路由
- 理解:value是component,用于展示页面内容
- 工作过程:当浏览器的路径改变的时候,对应的组件就会显示
二、基本使用
-
安装vue-router npm i vue-router -
引入 import VueRouter from 'vue-router' -
应用插件 Vue.use(VueRouter); -
创建并暴露一个router
import VueRouter from 'vue-router'
import Component1 from '../component/Component1'
import Component2 from '../component/Component2'
export default router= new VueRouter({
routes:[
{
path:'/component1',
component:Component1
},
{
path:'/component2',
component:Component2
}
]
})
-
实现切换 <router-link active-class="active" to="/component1">Component1</router-link>
-
指定显示位置 <router-view></router-view>
-
注意!
- 在开发中,路由组件通常放在src/pages下,一般的组件通常放在src/components下
- 切换路径进而切换显示的组件时,默认是在销毁、挂载组件
- 每个组件都有自己的$route属性,里面存储着自己的路由信息
- 整个应用只有一个router,通过每个路由组件的$router属性访问
三、多级路由
-
配置路由规则,在一级路由里使用children进行配置 export default router= new VueRouter({
routes:[
{
path:'/component1',
component:Component1,
children:[
{
path:'child1',
component:Child1
},
{
path:'child2',
component:Child2
}
]
}
]
})
-
跳转(to中的路径需要写完整) <router-link to="/component1/child1">Child1</router-link>
四、路由传参
1. query参数
2.路由命名(name配置项)
-
使用 export default router= new VueRouter({
routes:[
...
{
name:'c1',
path:'xxxx',
component:xxxxx
},
]
})
-
简化跳转
<router-link
:to="{
name:'c1',
query:{
...
}
}"
>Test1</router-link>
3.params参数
-
在配置中声明params参数 name:'c1'
path:'xxxx/:a/:b'
-
传递参数
<router-link :to="`/xxxx/${data.a}/${data.b}`">Test1</router-link>
<router-link
:to="{
name:'c1', //这里必须用name,不能用path!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
query:{
a:data.a,
b:data.b
}
}"
>Test1</router-link>
-
读取参数 this.$route.params.a
4.路由的props配置
作用,让路由组件更方便接收到参数
{
...
props($route){
return {
a:$router.query.xxx
b:$router.params.xxx
}
}
}
五、<router-link> 的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入模式:分别是
push 和replace ,push是追加记录(压栈),replace是替换,默认是push - 开启replace模式:
<router-link replace>.....</router-link>
六、编程式路由导航
-
作用:不需要再借助<router-link> ,路由跳转更加灵活 -
具体方法
this.$router.push({
name:'xxx',
query:{
...
}
})
this.$router.replace({
name:'xxx',
params:{
...
}
})
this.$router.back()
this.$router.forward()
this.$router.go()
七、缓存路由组件
八、activated与deactivated生命周期钩子
- 作用:路由组件独有,用于捕获路由组件的激活状态
activated 路由组件被激活时触发deactivated 路由组件失活时触发
九、路由守卫
1.全局守卫
router.beforeEach((to,from,next)=>{
})
router.afterEach((to,from)=>{
})
2.独享守卫
routes:[
...
{
...
beforeEnter(to,from,next){
...
}
}
]
3.组件内守卫
-
组件独享的守卫
beforeRouteEnter(to,from,next){}
beforeRouteLeave(to,from,next){}
十、路由器工作模式
- 对与一个路径来说,hash值就是#及其后面的内容
- hash值不会包含在HTTP请求中,即has值不会带给服务器
- hash模式
- 优点
- 缺点
- 如果以后将地址通过第三方手机app分享,如果app校验严格,则地址会标记为不合法
- 地址中带着/#/,不美观
- history模式
- 优点
- 缺点
- 兼容性略差
- 应用部署上线时需要后端人员支持,解决刷新页面服务器404问题(本质上是因为刷新时浏览器将路径全部发送给了服务器,请求服务器导致)
- 补充:Nodejs解决刷新页面服务器404问题方法(借助中间件)
- 比如:
connect-history-api-fallback npm上的connect-history-api-fallback
- 安装:
npm i connect-history-api-fallback - 引入:
const history = require('connect-history-api-fallback'); - 使用:
app.use(history()); (注意要在配置静态资源前使用)
(八)Vue的常用UI组件库
一、移动端常用UI组件库
二、PC端常用UI组件库
|