day01
一、框架介绍
1.什么是框架
框架,framework,它是一个网站的半成品,能够让开发人员能够专注于业务逻辑的处理。
2.vue框架
作者:尤雨溪
官网:https://cn.vuejs.org/
渐进式的Javascript框架
3.第四阶段主要学习内容
vue框架
vue、路由、vue-cli脚手架、axios、stylus、UI库、vuex状态管理、typescript、服务器端渲染
react框架
react、jsx语法糖、脚手架、路由
4.vue框架入门
vue两大核心:数据驱动页面,组件化开发
(1)优点
①体积小
②运行速度快(轻量级框架)
③虚拟DOM机制
④指令系统
⑤组件化开发
⑥生态系统繁荣
(2)缺点
①兼容性,不兼容ie8
②报错相对来说不是特别的清晰
(3)vue框架介绍
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
(4)安装vue
①直接引入外部js
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
②npm安装
npm i vue
安装好之后直接引入
<script src="./node_modules/vue/dist/vue.js"></script>
使用npm安装或者初始化项目前,一定要确认是否设置淘宝镜像地址(这样下载速度会比较快)
npm config set registry https://registry.npm.taobao.org
二、框架基本使用
1.实例化vue
new Vue({配置选项})
el:设置vue的作用范围,一般使用的id选择器,能够保证唯一性
el的挂载点不能是HTML、body这样的标签,应该是一个普通标签
2.设置初始数据
new Vue({
el:"#app",
data:{
msg:"这里是初始数据"
}
})
3.函数的声明和使用
自定义函数在methods选项中进行声明
new Vue({
el:"",
data:{},
methods:{
函数名称:function(){},
函数名称N(){}
}
})
使用自定义函数要在vue的挂载点内
<div id="app">
{{ 函数名称() }}
</div>
三、指令系统
1.内容展示
(1)文本插值语法 {{ }}
mustache语法,双花括号内,可以写单行js语法
<p>{{ 10 + 20 }}</p>
<p>{{ status ? '已登录' : '未登录' }}</p>
<p>{{ '欢迎:' + name }}</p>
<p>欢迎:{{name}}</p>
vue中的指令都是以v-开头,都写在标签的开始标签上,作为一个属性去使用。
<标签名 指令=“”></标签名>
(2)v-text
v-text会把指定的内容展示到指定标签内部,类似原生JS中的innerText
(3)v-html
v-html会把指定的内容展示到指定标签内部,同时,它可以解析html语法,类似原生js中的innerHTML
文本插值语法和v-text、v-html的区别
1.它们都可以在页面中展示指定的内容
2.不同的是,v-text和v-html用于展示固定内容,如果要展示内容是某段文字中的一部分时,要使用文本插值语法。
<p v-text='name'></p>
<p v-html="name"></p>
2.条件判断
(1)v-if
v-if、v-else
v-if、v-else-if
单路分支
<标签 v-if="布尔值或者条件表达式"></标签>
如果布尔值或者条件表达式返回值为true,指定的标签会在页面结构中存在,否则就不存在。
双路分支
<标签1 v-if="布尔值或者条件表达式"></标签1>
<标签2 v-else></标签2>
多路分支
<标签1 v-if="布尔值或者条件表达式"></标签1>
<标签2 v-else-if="布尔值或者条件表达式N"></标签2>
...
<标签2 v-else></标签2>
(2)v-show
<标签1 v-show="布尔值或者条件表达式"></标签1>
不论布尔值或者条件表达式的返回值是什么,标签都会在页面结构中存在
当布尔值或者条件表达式的返回值为true时,标签会在页面结构中显示
当布尔值或者条件表达式的返回值为false时,会给标签添加一个display:none属性
v-if 惰性加载,满足条件了才会在页面结构存在指定的标签
v-show 只是改变了display属性,如果需要频繁的控制元素显示/不显示时,推荐使用v-show
v-show不能和v-else配合使用
3.事件绑定
<标签 v-on:事件名="一行js代码或者自定义函数名称"></标签>
可以简写成:
<标签 @事件名="一行js代码或者自定义函数名称"></标签>
4.属性绑定
(1)普通属性绑定
当需要让标签的属性按照既定的规律进行变化时,可以通过v-bind进行绑定,这样属性绑定的变量值发生变化后,对应的属性也会跟着进行变化。
<标签 v-bind:属性名=“属性值”></标签>
可以简写成
<标签 :属性名=“属性值”></标签>
示例代码:
<div id="app">
<img v-bind:src="arr[showidx]" />
<button @click="showidx--">上一张</button>
<button @click="showidx++">下一张</button>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
showidx:0,
arr:[
'3.jpg',
'2.jpeg',
'1.jpg'
]
},
methods: {
//下一张的点击事件
next(){
if(this.showidx >= (this.arr.length-1)){
return;//不能让showidx数组下标无条件的累加,return之后的代码就不再执行了
}
this.showidx++;
},
//上一张的点击事件
prev(){
if(this.showidx<=0){
return;
}
this.showidx--;
}
}
})
</script>
此案例中,showidx就是要展示图片的下标值,当下标值发生变化时,就会根据下标从数组中获取对应的图片地址并绑定给src属性,数据变化后,页面会自动重新渲染。
(2)特殊属性绑定(动态样式绑定)
style
①变量的写法
<div id="app">
<p :style="styleFont">破纪录!袁隆平团队双季稻晚稻亩产911.7公斤</p>
<button @click="changeStyle('red')">红色</button>
<button @click="changeStyle('blue')">蓝色</button>
</div>
<script>
new Vue({
el:"#app",
data:{
styleFont:{color:'red'}
},
methods:{
changeStyle(color){
this.styleFont = { color }
}
}
})
</script>
②对象的写法
<p :style="{color:fontc,fontSize:'20px'}">破纪录!袁隆平团队双季稻晚稻亩产911.7公斤</p>
<p :style="{color:fontc,'font-size':'20px'}">破纪录!袁隆平团队双季稻晚稻亩产911.7公斤</p>
在对象写法中,属性名如果是多个单词,比如font-size、background-color、margin-left等,vue中需要把横杠和小写字母转换成大写字母:fontSize、backgroundColor、marginLeft。
③数组的写法
<p :style="[styleFont,styleSize]">破纪录!袁隆平团队双季稻晚稻亩产911.7公斤</p>
style的数组写法中,每一个数组元素都是一个变量,表示此标签可以使用多个行内样式。
class
①变量的写法
<style>
.red{ color:red }
</style>
<div id="app">
<p :class="className">港府公报:行政长官林郑月娥明起访问北京、广州和深圳</p>
</div>
<script>
new Vue({
el:"#app",
data:{ className:'red' }
})
</script>
②对象的写法
<style>
.big{ font-size:40px; }
.small{ font-size:15px;}
</style>
<div id="app">
<p :class="{big:false,small:true}">港府公报:行政长官林郑月娥明起访问北京、广州和深圳</p>
</div>
<script>
new Vue({
el:"#app"
})
</script>
布尔值或者表达式的结果为true时,表示使用指定的class属性,否则就不使用指定的class属性
③数组的写法
<style>
.big{ font-size:40px; }
.red{color:red;}
</style>
<div id="app">
<p :class="['big','red']">港府公报:行政长官林郑月娥明起访问北京、广州和深圳</p>
</div>
<script>
new Vue({
el:"#app"
})
</script>
5.列表渲染(循环)
v-for
语法格式:
<标签名 v-for="每次遍历的元素的变量名 of 数据源" ></标签名>
(1)数组
<标签名 v-for="(每次遍历的数组元素的变量名,遍历元素的下标) of 数据源" ></标签名>
(2)对象
<标签名 v-for="(每次遍历键值对中的键值,每次遍历键值对中的键名,每次遍历键值对的下标) of 数据源"></标签名>
(3)整数
<标签名 v-for="每次遍历键值对中的键值 of 整数值"></标签名>
如果想让某个标签遍历指定次数,可以直接遍历一个整数值,默认从1开始,每次递增1
示例代码:
<div id="app">
<!-- 遍历数组,最多支持两个参数,第一个是元素,第二个是下标 -->
<button v-for="(item,index) in arr">{{index}}---{{ item }}新闻</button>
<!-- 遍历对象,最多支持三个参数,第一个是键名,第二个是键值,第三个是下标 -->
<p v-for="(index,item,key) of info">{{key}}---{{ index }}---{{ item }}</p>
<!-- 遍历整数,默认从1开始进行遍历,每次递增1,到指定数值结束 -->
<p v-for="num in 10">{{ num }}</p>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
arr:[ '北京','中国','国际','热点'],
info:{
name:'小王',
age:18,
address:'北京市朝阳区'
}
}
})
// 原生js中of获取到是的元素内容,in获取到的是元素下标
// var arr2 = [ '北京','中国','国际','热点']
// for(item of arr2){
// console.log(item)
// }
</script>
常见错误
1.vue.js:634 [Vue warn]: Do not mount Vue to or - mount to normal elements instead.
vue的挂载点不能是html、body标签,应该是一个普通的标签
2.[Vue warn]: Property or method “msg” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
vue框架是一个声明式框架,变量或者函数要先声明然后再使用
3.[Vue warn]: Error compiling template:
v-else used on element without corresponding v-if.
v-else和v-else-if必须依存v-if才能使用
day02
一、表单元素双向绑定
1.设计模式
(1)MVC
smalltalk,把用户的输入、输出、处理分开
m model 数据模型层
v view 视图层(html、css、js)
c controller 控制器层
(2)MVVM
m model 数据模型层
v view 视图层
vm viewmodel 视图模型层
2.文本框
<input type="text" v-model="msg">
数据响应式原理:
原生JS示例代码:
<script>
let person = {
wh:"燕人",
get wh(){
console.log("获取外号....")
return "张飞";
},
set wh(val){
console.log("设置外号....",val)
}
}
console.log(person.wh)//读取数据,就会自动触发get方法
person.wh = "关羽"//设置数据,就会自动地触发set方法
</script>
3.文本域
textarea
<textarea cols="30" rows="10" v-model="content"></textarea>
4.复选框
checkbox
(1)多选
<div id="app">
<div>
<label>兴趣爱好:</label>
<input type="checkbox" v-model="hobbys" value="打游戏">打游戏
<input type="checkbox" v-model="hobbys" value="看电影">看电影
<input type="checkbox" v-model="hobbys" value="逛吃">逛吃
</div>
<div>
选择的是:{{ hobbys }}
</div>
</div>
<script>
new Vue({
el:"#app",
data:{
hobbys:[]
}
})
</script>
复选框的初始数据类型,一定是数组,这样才能够实现多选的情况
多选的情况下,checkbox一定要设置value属性
(2)单选
<div id="app">
<div>
<!-- 是否同意协议:<input type="checkbox" :checked="isagree"> -->
是否同意协议:<input type="checkbox" v-model="isagree">
</div>
</div>
<script>
new Vue({
el:"#app",
data:{
isagree:true
}
})
</script>
单选的情况下,checkbox不需要设置value属性
5.单选框
radio
<div id="app">
<div>
<label>状态:</label>
<!-- <input type="radio" name="status">正常
<input type="radio" name="status">禁用 -->
<input type="radio" value="1" v-model="status">正常
<input type="radio" value="2" v-model="status">禁用
</div>
<div>
选择的是:{{ status }}
</div>
</div>
<script>
new Vue({
el:"#app",
data:{
status:1
}
})
</script>
radio和checkbox(多选)一样,都是要设置value属性,这样在进行数据绑定时,才能够根据指定的数据,控制元素的选中效果。
6.下拉菜单
select > option
<div id="app">
<div>
<label>所学专业</label>
<select v-model="course">
<option value="">--请选择--</option>
<option value="1">web前端</option>
<option value="2">java开发</option>
<option value="3">ui设计</option>
</select>
</div>
<div>
选择的是:{{ course }}
</div>
</div>
<script>
new Vue({
el:"#app",
data:{course:""}
})
</script>
原生html中想让某个选项选中,需要在这个选项中添加selected属性
<option selected="selected">web前端</option>
在vue中直接给select标签添加v-model双向绑定,就可以给相应的选项设置选中效果
二、自定义指令
Vue.directive("指令名称",{
//inserted:function(el)
inserted(el){
//el就是使用自定义指令的标签元素
//js操作。。。
}
})
指令名称不需要添加v-前缀,但是在使用指令的时候需要添加v-前缀
inserted 被绑定元素插入父节点时就会调用该函数
bind 指定绑定到对应的元素后就会调用该函数
示例代码:
<div id="app">
<input type="text" v-focus>
</div>
<script>
Vue.directive("focus",{
inserted(el){
//el 就是使用该指令的标签元素
el.focus();
}
})
new Vue({
el:"#app"
})
</script>
示例代码2:
<div id="app">
<h1 v-color="'red'">{{ msg }}</h1>
<h1 v-color="'green'">{{ msg }}</h1>
</div>
<script>
Vue.directive("color",{
bind:function(el,binding){
//el 是使用自定义指令的元素
//binding 是自定义指令绑定的相关数据信息
el.style.color = binding.value;
}
})
new Vue({
el:"#app",
data:{
msg:'hello 自定义指令'
}
})
</script>
三、修饰符
1.事件修饰符
(1).prevent
阻止默认事件
(2).stop
阻止事件冒泡
(3).capture
捕获事件冒泡,影响事件冒泡的顺序
(4).self
事件触发者是元素本身时,对应的事件函数才会执行
(5).once
修饰指定事件、修饰符只执行一次
示例代码:
<div id="app">
<!-- 阻止默认事件 -->
<!-- 修饰符可以连贯起来使用,也就是给一个事件添加多个修饰符 -->
<button @contextmenu.prevent.once="menu">按钮</button>
<!-- 阻止事件冒泡 -->
<div class="outer" @click="outer">
<div class="inner" @click.stop="inner"></div>
</div>
<hr>
<!-- 捕获事件冒泡 -->
<div class="outer" @click.capture="outer">
<div class="inner" @click="inner"></div>
</div>
<!-- self -->
<hr>
<div class="outer" @click.self="outer">
<div class="inner" @click.once="inner"></div>
</div>
</div>
<script>
new Vue({
el:"#app",
methods: {
menu(){
console.log('右键被点击了....');
},
outer(){
console.log("outer....")
},
inner(){
console.log("inner....")
}
},
})
</script>
2.表单元素修饰符
(1).lazy
不再对表单元素进行实时的数据双向绑定,只有遇到change事件时,才会进行数据的双向绑定
(2).number
number修饰符可以保持数据类型为number,如果输入的内容中是以数字开头,非数字结尾,可以把非数字内容进行过滤。
(3).trim
过滤输入内容左右两边的空格
3.其他修饰符
(1)鼠标修饰符
.left
.middle
.right
(2)键盘修饰符
keydown、keyup
.esc
.enter
.space
.backspace
.left
.right
.down
.up
.delete
day03
一、监听器
侦听器
作用:检测变量值的变化,只要数据变化,就可以触发相应的函数执行一定的操作。
作为vue实例的配置选项,watch
1.普通监听
可以检测标量类型数据的变化:字符串、数字(整数、浮点数)、布尔值
当依赖的数据发生变化时,就会触发对应的函数
①写法一
<script>
new Vue({
el:"",
data:{ipt:''},
watch:{
ipt([newVal,oldVal]){
....
}
}
})
</script>
②写法二
<script>
new Vue({
el:"",
data:{ipt:''},
watch:{
ipt:{
handler([newVal,oldVal]){...}
}
}
})
</script>
2.深度监听
如果要监听的数据类型是复合类型时,普通的监听方式是无法实现,需要使用第二种写法并添加deep配置选项,来实现监听复合类型数据的变化。
复合类型:对象、数组
<script>
new Vue({
el:"",
data:{
info:{ name:'' }
},
watch:{
info:{
handler:function([newVal,oldVal]){...},
deep:true//显示的设置为深度监听
}
}
})
</script>
二、数据变化后页面不更新
解决办法:
(1)$set
vue.$set(target,key,value)
target是要改变的数据
key是数组的下标
value是要改变的内容
(2)$forceUpdate
强制重新渲染页面
(3)使用数据的相关api方法(push、shift、unshift…)
三、计算属性
1.基本使用
页面上有频繁需要进行计算得到结果,可以使用计算属性
computed
<div id="app">
{{ 要计算的结果变量名 }}
</div>
<script>
new Vue({
el:"",
computed:{
要计算的结果变量名1(){
计算逻辑...
return 计算结果
},
要计算的结果变量名N(){
计算逻辑...
return 计算结果
},
}
})
</script>
2.计算属性和监听的区别
相同:依赖的数据发生变化时,对应的函数会自动执行
不同:触发场景不同,监听是在页面渲染完成后,数据发生变化时,才会触发对应的函数
计算属性,只要页面中使用了计算属性的结果,或者依赖的数据发生变化时,就会触发对应的函数。
3.计算属性与函数的区别
计算属性依赖的数据,不发生变化时,不会重新执行相应的函数,因为计算属性在vue实例上产生了一个缓存。
函数调用几次,就会执行对应的函数几次,在性能上消耗比计算属性大很多。
计算属性的结果不能直接赋值
四、过滤器
作用:在页面展示数据前,可以通过过滤器对要展示的数据进行二次处理,满足一定的需求后再展示出数据。
1.定义
(1)全局定义
Vue.filter("过滤器名称",function(形参1){...})
(2)局部定义
<script>
new Vue({
el:"",
data:{},
methods:{},
watch:{},
computed:{},
filters:{
过滤器名称:function(实参1){
处理逻辑...
return 处理结果
}
}
})
</script>
2.使用
在挂载点内,通过管道符“|” 来使用定义好的过滤器。
{{ 要展示的变量 | 过滤器名称 }}
3.过滤器的参数
在过滤器中,第一个参数默认是管道符左边的数据
如果要传递额外的其他参数时,需要像使用函数传参一样,把过滤器名称当成函数名称,然后在后面传递额外的参数。
示例代码:
<div id="app">
<p>
<!-- 调用过滤器后,就会展示一个两位小数的价格 -->
价格:{{ price | formatPrice }}
</p>
<p>
<!-- 调用过滤器后,就会展示一个一位小数的价格 -->
价格:{{ price | formatPrice(1) }}
</p>
</div>
<script>
new Vue({
filters:{
formatPrice:function(price,n=2){
return '¥' + price.toFixed(n) + '元';
}
},
el:"#app",
data:{ price:288 }
});
</script>
五、生命周期
vue实例从创建、挂载、更新、销毁的一个完整的过程叫做生命周期。
钩子函数(在指定的场景下会自动触发的函数)
1.页面渲染期
beforeCreate vue实例创建之前
created vue实例创建完成
beforeMount vue实例挂载到挂载点之前
mounted vue实例挂载到挂载点之后
2.页面更新期
beforeUpdate 数据更新之前
updated 数据更新完成
3.页面销毁期
beforeDestroy 页面销毁之前
destroyed 页面销毁完成
day04
一、过渡动画
使用场景:v-if、v-show、动态组件、组件根节点
1.内置类名
<transition>
<要使用过渡动画效果的标签></要使用过渡动画效果的标签>
</transtion>
(1).匿名动画
进入
进入开始 v-enter
进入进行中 v-enter-active
进入结束 v-enter-to
离开
离开开始 v-leave
离开进行中 v-leave-active
离开结束 v-leave-to
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.box{
width: 300px;
height: 300px;
background-color: red;
}
.v-enter,.v-leave-to{ opacity: 0; }
.v-enter-active,.v-leave-active{ transition:1.5s linear; }
.v-enter-to,.v-leave{ opacity: 1; }
</style>
</head>
<body>
<div id="app">
<transition>
<div class="box" v-if="show"></div>
</transition>
<button @click="show=!show">切换</button>
</div>
<script>
new Vue({
el:"#app",
data:{
show:true
}
})
</script>
</body>
</html>
(2)具名动画
页面中有多个标签要设置不同的过渡动画效果时,需要给transition标签设置name属性,设置name属性之后,内置类名的前缀就要改为对应的name属性。
<style>
/* 具名过渡动画 */
.move-enter,.move-leave-to{left:0;}
.move-enter-active,.move-leave-active{ transition:1.5s linear;background-color: blue; }
.move-enter-to,.move-leave{ left: 600px; }
</style>
<transition name="move">
<div class="box2" v-if="show"></div>
</transition>
2.animate.css动画库
(1)安装
npm i animate.css
(2)引入
<link rel="stylesheet" href="./node_modules/animate.css/animate.css">
(3)使用
需要给transition标签设置两个属性
enter-active-class 进入的动画
leave-active-class 离开的动画
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过渡动画-动画库</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" href="./node_modules/animate.css/animate.css">
<style>
.box{
width: 300px;
height: 300px;
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<button @click="show=!show">切换</button>
<transition
enter-active-class="animate__animated animate__bounceInUp"
leave-active-class="animate__animated animate__bounceOutLeft"
>
<div class="box" v-if="show"></div>
</transition>
</div>
<script>
new Vue({
el:"#app",
data:{
show:true
}
})
</script>
</body>
</html>
二、组件【重点】
1.介绍
组件即零件,组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用
组件是可复用的 Vue 实例
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
2.注册
(1)局部注册
new Vue({
components:{
组件名称1:{
template:"组件模板内容"
},
组件名称N:{
template:"组件模板内容"
}
}
})
(2)全局注册
Vue.component("组件名称1",{ template:"组件模板内容" })
Vue.component("组件名称N",{ template:"组件模板内容" })
3.使用
在vue的挂载点内,以标签的方式来使用组件
在vue的挂载点内使用组件后,组件名称的所在位置会被组件的template内容进行替换。
示例代码:
<div id="app">
<!-- 使用组件 -->
<mycom></mycom>
<mycom></mycom>
<mycom></mycom>
</div>
<script>
new Vue({
el:"#app",
components:{
mycom:{
// 组件的template中只能有一个根标签
template:"<div><h1>这是一个自定义组件</h1><h2>标题2</h2></div>"
}
}
})
</script>
4.注册组件注意事项
(1)组件名称不能是系统内置的标签名
(2)组件名称不能是系统内置的大写的标签名
(3)如果组件名称中包含了大写字母,在使用要把大写字母转换成-小写字母
(4)template内容中只能有一个根标签
5.template的使用
(1)vue实例的template选项
组件中可以通过template属性来设置该组件的模板内容
vue实例上也可以设置一个template属性,用来把指定的template对应的内容或者组件,替换到vue实例的挂载点内。
示例代码:
<script>
new Vue({
el:"#con",
// template:"<h2>vue实例的template属性</h2>"
template:"<my-div />",
components:{
myDiv:{
template:"<h1>自定义组件</h1>"
}
}
});
</script>
(2)template标签
如果组件中的模板内容比较多时,使用字符串的方式编写html代码会很麻烦,且没有任何语法提示,如果代码编写不够熟练,非常容易出现错误。
vue中给提供了一个template标签,用来存放组件的模板内容
示例代码:
<div id="app">
<mycom></mycom>
</div>
<template id="mycom">
<div>
<h1>自定义组件</h1>
</div>
</template>
<script>
new Vue({
el:"#app",
components:{
mycom:{
// 让组件的template属性和template标签关联起来
template:"#mycom"
}
}
})
</script>
6.组件的key属性
组件遍历循环时,需要给组件添加一个唯一的标识,能够加快页面的渲染速度
7.组件中的data应该是一个函数
由于对象是引用类型,所以在data中以对象的方式定义初始数据,然后在组件中使用数据并复用这个组件时,会产生数据上的冲突(也就是一个数据改变了之后,其他的也跟着进行变化)
所以,在组件中定义初始数据,需要以函数的方式返回一个新的对象来定义数据,这样每复用一次组件,就会调用一次data的函数并返回一个新的数据存储空间,这样组件与组件之间的数据就不会互相影响了。
实例代码:
<div id="app">
<v-box></v-box>
<v-box></v-box>
<v-box></v-box>
</div>
<template id="box">
<div class="box">
<p>数量:{{ num }}</p>
<button @click="num++">增加数量</button>
</div>
</template>
<script>
new Vue({
el:"#app",
components:{
vBox:{
template:"#box",
data:function(){
return{
num:100
}
}
}
}
})
</script>
注意:在组件中,不能直接使用vue根实例上的data数据,因为组件也是一个vue实例,实例与实例之间的数据是不共享的。
三、vue-cli脚手架
最新版本:4.X
稳定版本:2.9.6
1.安装
node环境
(1)webpack
npm i webpack -g
(2)vue-cli
npm i vue-cli -g
2.初始化项目
进入到一个指定的目录中,然后进入命令行
vue init webpack mydemo
安装过程:
Project name (mydemo) 项目名称,如果不需要修改直接回车
Project description (A Vue.js project) 项目描述,如果不需要修改直接回车
Author (fan <fanmingjian@offcn.com>) 项目作者,如果不需要修改直接回车
Vue build (Use arrow keys) vue构建方式,选择默认的热编译
> Runtime + Compiler: recommended for most users
Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - re
nder functions are required elsewhere
Install vue-router? (Y/n) 是否安装vue路由,输入n
Use ESLint to lint your code? (Y/n) 是否安装eslint代码验证工具,输入n
Set up unit tests (Y/n) 是否创建单元测试,输入n
Setup e2e tests with Nightwatch? (Y/n) 是否创建端对端测试,输入n
Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys) 选择依赖安装方式,选择npm
> Yes, use NPM
Yes, use Yarn
No, I will handle that myself
3.运行项目
在命令行中,进入项目根目录,执行如下命令:
npm run dev
localhost:8080
4.目录结构
mydemo
build 项目打包主程序目录
config 项目配置文件目录
node_modules 项目依赖目录
src 项目源码目录
assets 项目静态资源目录(参与打包)
components 项目组件目录
App.vue 项目根组件
main.js 项目启动文件
static 项目静态资源目录
index.html 项目首页
package.json项目依赖配置文件
项目运行流程:
index.html
/src/main.js
/src/App.vue
5.vue组件构成
在脚手架中,组件以单独的.vue后缀的文件存在,组件由三部分组成:
template模板,只有一个,所以不需要设置id属性
script 组件逻辑代码【非必须】
style 组件样式代码【非必须】
所有的组件都要先从App.vue开始,它是脚手架的根组件,在App.vue要引用其他组件的话需要使用import关键词
示例代码:
创建一个Home组件
/src/components/Home.vue
<template>
<div>
<h1>home组件</h1>
<v-top></v-top>
</div>
</template>
<script>
import vTop from './Top'
export default {
components:{ vTop}
}
</script>
/src/App.vue
<script>
// 引入Home组件
import Home from './components/Home'
export default {
components: {
Home
}
}
</script>
<template>
<div id="app">
<Home />
</div>
</template>
<style>
/* 全局样式 */
h1 { color: red;}
</style>
常见错误
1.[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the “name” option.
组件没有正确的注册就使用了
2.vue.js:634 [Vue warn]: Do not use built-in or reserved HTML elements as component id: div
不使用系统内置标签作为组件名称
3.[Vue warn]: The “data” option should be a function that returns a per-instance value i
day05
一、组件通信【重点】
场景:由于组件与组件数据不共享,当需要复用组件并让组件中的内容不一样时,可以使用组件通信来实现。
1.父子组件
自定义属性和props
第一步:先创建两个组件,一个父组件parent.vue,一个子组件child.vue
在App.vue中引入父组件,并使用它
<script>
import vParent from './components/parent'
export default {
components: {
vParent
}
}
</script>
<template>
<div class="page">
<v-parent></v-parent>
</div>
</template>
第二步:在父组件中引入子组件,构建父子组件的关系,并通过自定义属性传递数据
/src/components/parent.vue
<template>
<div>
<h1>父组件</h1>
<!-- 在父组件使用子组件时,通过自定义属性来传递数据 -->
<v-child v-for="(item,index) of newsarr" :key="index"
:newstitle="item"
></v-child>
</div>
</template>
<script>
import vChild from './child'
export default {
components:{ vChild },
data(){
return{
newsarr:['国内','北京','国际','娱乐']
}
}
}
</script>
第三步:在子组件child.vue中通过props选项来接收父组件传递数据,并在子组件中使用这些数据
/src/components/child.vue
<template>
<div class="box">
<h1>{{ newstitle }}新闻</h1>
</div>
</template>
<script>
export default {
// 在子组件中通过props来接收父组件传递的数据
// 子组件接收到数据后,就可以直接在子组件的模板中使用该数据了
props:['newstitle']
}
</script>
<style>
.box{
border:1px solid #000;
margin:20px;
padding:20px;
}
</style>
props验证
子组件可以对父组件传递的数据进行一些验证:数据类型、默认值、自定义验证。。。
(1)验证数据类型
<script>
export default {
props:{
// 验证数据类型,可以验证常见的数据类型:
//字符串String 数字Number 布尔值 Boolean 对象 Object 函数 Function等
newstitle:String
}
}
</script>
验证多个数据类型
如果要接收的变量是多个数据类型,则需要这样去进行验证
<script>
export default {
props:{
newstitle:[String,Number]//此时父组件传递的数据既可以是字符串,也可以是数字
}
}
</script>
(2)验证必填
<script>
export default {
props:{
viewnum:{
required:true,
type:Number//验证必填的同时还可以验证数据类型
}
}
}
</script>
如果子组件中有一个父组件必须传递的数据,可以通过required来进行验证。
(3)默认值
<script>
export default {
props:{
viewnum:{
required:true,
type:Number//验证必填的同时还可以验证数据类型
},
first:{
// default:"什么也没有"
//如果数据类型是对象或者数组时,默认值是一个函数,返回对应的数据格式
default:function(){
return{
title:'什么也么有'
}
}
}
}
}
</script>
(4)自定义验证规则
<script>
export default {
props:{
viewnum:{
required:true,
type:Number,//验证必填的同时还可以验证数据类型
validator:function(val){
//自定义验证规则,只要返回值为false就会出现警告
return val > 1 && val <= 999;
}
}
}
}
</script>
props验证给出只是警告,不影响程序的运行。
2.子父组件
自定义事件、$emit
第一步:在父组件使用子组件的时候,传递一个自定义函数,并在父组件中定义好对应的函数操作
<v-child v-for="(item,index) of newsarr" :key="index"
:newstitle="item.title" :num="item.num"
:newsidx="index"
@addbychild="addnum"
></v-child>
<script>
export default {
components:{ vChild },
methods:{
addnum(n){
this.newsarr[n].num++;
}
},
data(){
return{...}
}
</srcipt>
第二步:在子组件中通过vue实例上的$emit方法,来触发父组件传递的事件函数
<template>
<div class="box">
<span>{{ newstitle }}</span>
<span>访问量:{{ num }}</span>
<button @click="add">访问</button>
</div>
</template>
<script>
export default {
props:['newstitle','num','newsidx',"arr"],
methods:{
add(){
//触发父组件传递的事件函数,并传递参数
this.$emit("addbychild",this.newsidx)
}
}
}
</script>
3.非父子组件
公用的容器(eventbus)、 e m i t 、 emit、 emit、on
第一步,创建一个公用的容器
/src/main.js实例化vue之前
Vue.prototype.$ev = new Vue();
第二步:在数据发送的组件中,通过公用容器进行数据发送
this.$ev.$emit("事件名称","要传递的数据")
第三步:在数据接收的组件的挂载完成生命周期中实现数据的接收
mounted() {
//通过容器,一直监听数据,只要有数据的发送,就可以收到数据
this.$ev.$on("时间名称",(str)=>{
...
})
}
二、组件进阶
1.is属性
改变html标签默认结构约束
动态组件
示例代码:
menu.vue
<template>
<div class="menu">
<a @click="tab('setting')">系统设置</a>
<a @click="tab('student')">学生管理</a>
<a @click="tab('course')">课程管理</a>
</div>
</template>
<script>
export default {
methods:{
tab(tag){
console.log(tag,'发送')
this.$ev.$emit("changeTag",tag)
}
}
}
</script>
<style>
.menu{
text-align: center;
}
.menu a{
display: block;
color:#fff;
font-size: 20px;
margin:10px;
cursor: pointer;
}
</style>
main.vue
<template>
<div class="main">
<v-menu></v-menu>
<div class="right">
<!-- 动态组件 -->
<div :is="tagname"></div>
</div>
</div>
</template>
<script>
import vMenu from './menu'
import setting from './setting'
import student from './student'
import course from './course'
export default {
components:{
vMenu,setting,student,course
},
mounted() {
this.$ev.$on("changeTag",(t)=>{
console.log(t,'接收')
this.tagname = t;
})
},
data(){
return{
msg:'hello',
tagname:'setting'
}
}
}
</script>
<style>
.main{
flex:1;
display: flex;
}
.menu{
width:120px;
background-color: #000;
}
.right{
flex:1;
}
</style>
2.ref
vue中提供了一个ref属性,可以给标签添加ref属性,来实现原生JS的一些操作或者父子组件通信的效果。
(1)字符串
<h1 ref="myh1">系统设置页面</h1>
此时在$refs中就会增加了一个myh1的内容,它的值就是DOM元素。
(2)数组
<ul>
<li ref="lis" v-for="item of numarr" :key="item">{{ item }}</li>
</ul>
如果ref应该在一个遍历循环上,则会在$refs中增加一个数组,数组的每个元素都是一个DOM元素
(3)组件【常用】
给自定义组件添加ref属性后,可以利用DOM操作的方式,来给组件进行数据的传递
<template>
<div>
<v-item ref="myitem"></v-item>
</div>
</template>
<script>
import vItem from './item'
export default {
components:{ vItem },
mounted(){
//直接在父组件中通过ref来给子组件进行数据的传递
this.$refs.myitem.msg = '系统设置-数据'
}
}
</script>
3.jquery
如果有一些页面效果,不知道用vue如何实现,但是知道用jquery去实现,那么在vue中可以用jquery来进行操作。
(1)安装
npm i jquery
(2)使用
<script>
//引入jquery
import $ from 'jquery'
export default {
methods:{
toggle(){
this.jQuery(".box").slideUp(2000)
}
}
</script>
<template>
<div>
<button @click="toggle">toggle</button>
<div class="box"></div>
</div>
</template>
<style>
.box{
width: 200px;
height: 200px;
background-color: #f00;
}
</style>
#