Vue
1.语法格式
每个Vue应用都需要通过实例化Vue来实现,Vue实例和容器是一一对象的关系。
语法格式如下:
var vm = new Vue({
//选项
})
2.构造器需要的内容
- data:用于定义属性
- methods:用于定义函数,可以通过return来返回函数值
- ({}):用于输出对象和函数返回值
- Vue提供了一些有用的实例方法,他们都有前缀$,以便与用户定义的属性区分开来。
- 遇到v-bind时候属性括号中的当做js表达式
3.插值语法和指令语法
- 插值语法:{{}}:凡是在标签体中插入的内容都用插值语法
- 指令语法:v-bind:可以简写成一个冒号,一般用于解析标签,比如标签属性,标签体内容,绑定事件
4.单向数据绑定双向数据绑定
- 利用v-bind绑定属性之后,为单向数据绑定,当页面的输入框的值发生改变的时候,data中的值不改变
- 使用v-model绑定属性之后,为双向数据绑定,当表单值改变或者data值改变的时候另一边都会跟着改变
- 另外需要注意的是,双向绑定一般只用于表单类元素
//简写方式
<a :href="url">一点点内容</a>
<a v-medol="title">亿点点内容</a>
el的两种写法
var data = {title:"第一个标题",url:"werewt"}
var vm = new Vue({
// el:"#app",
data:data,
methods:{
ht:function(){
return this.title+",就是随便写的,哈哈哈哈哈!"
}
}
})
vm.$mount("#app")
data两种写法
var vm = new Vue({
// el:"#app",
data:data,
methods:{
ht:function(){
return this.title+",就是随便写的,哈哈哈哈哈!"
}
}
})
vm.$mount("#app")
var vm = new Vue({
el:"#app",
data(){
return{
data
}
}
})
在这个函数中this指向的Vue实例,因为是Vue实例调用了这个函数,如果是箭头函数的话,this指向就不再是Vue,二是windows
4.MVVM模型
5.关于Object.defineProperty技术
let data = {title:"第一个标题",url:"werewt"}
Object.defineProperty(data,"method",{
value:34,
enumerable:true,//定义属性是否可以被枚举
writable:true,//定义属性是否可以被修改
configurable:true//定义属性是否可以被删除
})
//三种属性默认值都是false
console.log(data);
6.数据代理
通过一个对象代理另一个对象属性的操作
例子:
//数据代理
let obj1 = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,"x",{
get(){
return obj1.x
},
set(value){
obj1.x = value
}
})
7.事件修饰符
1.阻止默认事件
<div id="app">
<p @onclick.prevent="showe()">{{title}}</p>
<p>{{url}}</p>
<p>{{ht()}}</p>
<a :href="url">一点点内容</a>
<a v-medol="title">亿点点内容</a>
</div>
var vm = new Vue({
el:"#app",
data:{
ti:"sdd"
},
methods:{
showe(e){
e.preventDefault()
alert("fff");
}
}
})
2.阻止事件冒泡
<div id="app"@onclick="showe()">
<p @onclick.stop="showe()">{{title}}</p>
<p>{{url}}</p>
<p>{{ht()}}</p>
<a :href="url">一点点内容</a>
<a v-medol="title">亿点点内容</a>
</div>
var vm = new Vue({
el:"#app",
data:{
ti:"sdd"
},
methods:{
showe(e){
e.stopPropagation()
alert("fff");
}
}
})
3.事件触发一次
<div id="app">
<p @onclick.once="showe()">{{title}}</p>
<p>{{url}}</p>
<p>{{ht()}}</p>
<a :href="url">一点点内容</a>
<a v-medol="title">亿点点内容</a>
</div>
修饰符可以连写
<div id="app">
<input type="text" @keyup.ctrl.y = "kf">//表示只有按下ctrl+y的时候才能触发事件
</div>
6.Vue中常用的按键别名
- 回车------enter
- 删除------delete
- 退出------esc
- 空格------space
- 换行------tab(比较特殊,需要配合keydown使用)
- 上------up
- 下------down
- 左------left
- 右------right
Vue未提供别名的按键,可以使用按键原石的key值绑定,但是要注意转化为kebab-case(端横线命名法)
7.Vue的计算属性
- 字符拼接
<body>
<div id="app">
姓:<input type="text" name="" id= "" v-model = "firstname"><br>
名:<input type="text" name="" id="" v-model = "lastname"><br>
全名:<span>{{fullname()}}</span>
</div>
<div id="app1">
姓:<input type="text" name="" id= "" v-model = "firstname"><br>
名:<input type="text" name="" id="" v-model = "lastname"><br>
全名:<span>{{fullname}}</span>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
firstname:"张",
lastname:"三"
},
methods:{
fullname(){
return this.firstname+"-"+this.lastname;
}
}
})
var vm = new Vue({
el:"#app1",
data:{
firstname:"张",
lastname:"三"
},
computed:{
fullname:{
//当有人读取fullname是,get就会被调用,返回值作为fullname的值
//get什么时候会被调用?初次读取fullname时,或者所依赖的对象发生变化时
get(){
console.log("get被调用了");
return this.firstname+"-"+this.lastname
},
//set什么时候被调用?当fullname被修改时
set(value){
console.log('set',value);
const arr = value.split('-')
this.firstname = arr[0]
this.lastname = arr[1]
}
}
}
})
</script>
- 定义:要用的属性不存在,要通过已有的属性来计算得来。
- 原理:底层借助了object.defineproperty方法提供的getter和setter
- get函数什么时候执行?
- 初次独处时会执行一次
- 当依赖的数据发生改变时会再次调用
- 优势:与methos实现相比,内部有缓存机制(复用),效率更高,调用方便
- 备注:
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那么必须写set函数去想用修改,set中要引起计算时依赖的数据发生变化。
当页面中没用使用Vue中的data属性的时候,在开发者工具中显示的数据不会改变,但是实际上数据是已经改变的。
8.监听属性
- 当被见识的属性发生变化时,毁掉函数自动调用,进行相关操作
- 简书的属性必须存在,才能进行监视
- 监视的两种写法:
- new Vue时传入watch配置
- 通过vm
- 通过vm.$watch监视
深度监视
监视多级结构中某个具体的属性的变化
const vm = new Vue({
el:"#rood",
data:{
isHot:true,
number:{
a:1,b:2
}
},
computed:{
info(){
return this.isHot?'炎热':'凉爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
//监视多级结构中某个属性的变化
watch:{
isHot:{
'number.a':{
handler(){
console.log("a的值发生了变化");
}
}
}
}
})
监视多级结构中所有属性的变化
watch:{
number:{
deep:true,
handler(){
console.log("a的值发生了变化");
}
}
}
}
总结:
- Vue中的watch默认不检测对象内部的改变(一层)
- 配置deep:true可以检测对象内部值改变(多层)
- Vue自身课检测对象内部值的改变,但Vue提供的watch默认不可以、
- 使用watch时根据数据的具体结构,来决定是否采用深度监测
计算属性不同异步实现,如果结果是通过异步来完成的需要使用watch
定时器所管理的函数,不受Vue管理
属性:
deep:值为true或者false,确认是否深度监听,一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到
immediate:值为true或者false,确认是否以当前的初始值执行handler的函数,当值为true的时候,则会立即执行,当页面刷新时会立即执行一次handler函数
Computed和watch的区别
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,比如:watch可以进行衣服操作。
- 被Vue所管理的函数,最好携程普通函数,这样this的指向才是vm或者组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数),最好携程箭头函数,这样this的指向才是vm或者组件的实例对象76
9.绑定样式
绑定class样式的两种写法
-
字符串写法,适用于:样式的类名不确定,需要动态绑定
-
对象写法:要绑定的样式个数确定,名字也确定,但要动摇决定用不用
-
数组写法
绑定style样式的两种写法(样式对象中的属性不能随便写,需要是css有的属性)
- 对象写法
- 数组写法
不变的东西静态写,变化的东西使用vm管理
10.条件渲染
两种方式
- v-show
- v-if
相同点:当判断结果为true的时候都能使内容在页面上显示,为false都能使内容消失,但是v-if能直接使这个结构消失,而v-show修饰,结构还在,只是不显示而已
v-if:
有v-if,v-else-if,v-else三种,和条件语句一样,可以组成一组判断
但是当v-if和v-else后面的条件都不成立时,不管v-else后面的条件成立与否,都会执行v-else之后的语句
但是v-if和v-else-if中间不能有没有v-if的语句
template标签:当多个标签元素想要同时实现显示和消失的时候,如果给每个标签都添加v-show说着v-if的话太过于麻烦,如果手动用div包裹在div上添加v-if会强行改变文档结构,所以可以采用template标签来把这几个标签包裹起来,并且用template包裹起来的标签不会改变文档的结构,template标签在文档中不显示结构
但是template标签不能使用v-show只能搭配v-if使用
总结:
-
写法
- v-if=“表达式”
- v-else-if=“表达式”
- v-else=“表达式”
适用于:切换频率较低的场景
特点:不展示Dom元素直接被移除
注意:v-if可以和v-else-if,v-else一起使用,但要求结构不能被打断
-
v-show
写法:v-show=“表达式”
适用于:刷新频率较高的场景
特点:不展示DOM元素,未被移除,仅仅是使用样式隐藏掉
-
备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到。
11.列表渲染
分以下几种情况:
- 遍历数组
- 遍历对象
- 遍历字符串
- 遍历指定次数
语法:
<div id="rood">
<h2>遍历字符串</h2>
<ul>
<li v-for = "(char,index) of str">
{{char}}-{{index}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el:"#rood",
data: {
str:"helloworld"
},
})
</script>
<h2>遍历指定次数</h2>
<ul>
<li v-for = "(a,b) of 4">{{a}}-{{b}}</li>
//第一个表示从一开始,第二个是索引
</ul>
12.key的作用与原理
给节点一个表示,相当于身份证号
原理:
- 初始数据在传到页面的时候首先会先生成一个虚拟DOM,在虚拟DOM中会给每个节点添加key值,但是这个key值在虚拟DOM转化为真实DOM的时候不会跟着一起显示
- 用户能够操作的一定是真实DOM
- 当用户想要在首位插入新数据的时候,再次生成的虚拟DOM的每个虚拟节点的key值会变换,新插入的key值为0,由于Vue中的对比算法,在顺序错乱的时候会出错
虚拟DOM中key的作用:
- key是虚拟DOM对象的表示,当状态中的数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM的差异比较
对比规则:
-
旧虚拟DOM中找到了与新虚拟DOM相同的key
- 若虚拟DOM中内容没改变,直接使用之前的真实DOM
- 若虚拟DOM中的内容改变了,则生成新的真实DOM,随后替换掉页面之前的真实DOM
-
旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面上
用index作为key可能会引发的问题
-
若对数据进行:你需添加,逆序删除等破坏顺序的操作
会产生没有必要的真实DOM更新,界面效果没问题,但效率低
-
如果结构中还包含输入类的DOM
会产生错误的DOM更新,从而导致界面有问题
开发中如何选择key:
- 最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等,唯一值。
- 如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key 是没有问题的
13.列表过滤
可以使用两种方法实现:watch和computed
监视和计算
当watch和computed都能实现优先使用computed
代码:
<div id="rood">
<input type="text" placeholder="请输入名字" v-model = 'keywords'>
<ul>
<li v-for = "person of filPeople">{{person.name}}-{{person.sex}}-{{person.age}}</li>
</ul>
</div>
<script>
//用watch实现
// new Vue({
// el:"#rood",
// data: {
// keywords:'',
// str:"helloworld",
// people:[
// {id:'001',name:"马冬梅",sex:'女',age:'19'},
// {id:'001',name:"周冬雨",sex:'女',age:'20'},
// {id:'001',name:"周杰伦",sex:'男',age:'21'},
// {id:'001',name:"温兆伦",sex:'男',age:'22'}
// ],
// filPeople:[]
// },
// watch:{
// keywords:{
// immediate:true,
// handler(val){
// this.filPeople = this.people.filter((p)=>{
// return p.name.indexOf(val) !== -1
// })
// }
// }
// }
// })
//用computed实现
new Vue({
el:"#rood",
data: {
keywords:'',
str:"helloworld",
people:[
{id:'001',name:"马冬梅",sex:'女',age:'19'},
{id:'001',name:"周冬雨",sex:'女',age:'20'},
{id:'001',name:"周杰伦",sex:'男',age:'21'},
{id:'001',name:"温兆伦",sex:'男',age:'22'}
]
},
computed:{
filPeople(){
return this.people.filter((p)=>{
return p.name.indexOf(this.keywords) !== -1
})
}
}
})
</script>
功能升级:
在实现查询之后可以按照一定的顺序进行排序
new Vue({
el:"#rood",
data: {
keywords:'',
sortType:0,
str:"helloworld",
people:[
{id:'001',name:"马冬梅",sex:'女',age:'23'},
{id:'001',name:"周冬雨",sex:'女',age:'32'},
{id:'001',name:"周杰伦",sex:'男',age:'43'},
{id:'001',name:"温兆伦",sex:'男',age:'28'}
]
},
computed:{
filPeople(){
const arr = this.people.filter((p)=>{
return p.name.indexOf(this.keywords) !== -1
})
//判断是否需要排序
if (this.sortType) {
arr.sort((a,b)=>{
return this.sortType ===1?b.age-a.age:a.age-b.age
})
}
return arr
}
}
})
Vue监测数据改变的原理
Vue默认可以检测数据变化,Vue在创建好实例的时候会自动生成set和get方法,然后只要Vue监测到数据发生变化就会自动调用get或者set方法进行修改
Vue有一个特点就是,如果数据是undefined,则不会在页面上展示出来
添加属性
methods: {
addSex(){
Vue.set(this.people,"sex","男")
}
},
Vue.set只能给data里面的属性添加值,不能直接给data添加属性和值
如果想要修改或者添加数组中的数据,需要用数组的方法
通过Vue.set()也可以实现对数组中数据进行修改
<div id="rood">
<h1>学生信息</h1>
<button @click = "student.age++">年龄+1</button>
<button @click = "addSex()">点击添加性别</button>
<button @click.once = "addFriend()">点击添加一个朋友</button>
<button @click="updateFirstFriend()">点击修改第一个朋友的信息</button>
<button @click.once = "addHobby()">点击添加一个爱好</button>
<button @click = "updateFirstHobby()">修改第一个爱好为开车</button>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<h3>爱好:</h3>
<ul>
<li v-for = "(h,index) of student.hobby">{{h}}</li>
</ul>
<h3>朋友:</h3>
<ul>
<li v-for = "(f,index) of student.friends">{{f.name}}-{{f.age}}</li>
</ul>
</div>
<script>
let vm = new Vue({
el:"#rood",
data: {
student:{
name:"zhangsan",
age:"23",
hobby:["爱好1","爱好2","爱好3"],
friends:[
{name:"lisi",age:"13"},
{name:"wangwu",age:"23"}
]
}
},
methods: {
addSex(){
Vue.set(this.student,"sex","男")
},
addFriend(){
this.student.friends.unshift({name:"zhaoliu",age:"70"})
},
updateFirstFriend(){
this.student.friends[0].name = "诶嘿"
this.student.friends[0].age = "3"
},
addHobby(){
this.student.hobby.unshift("喝酒")
},
updateFirstHobby(){
this.student.hobby.splice(0,1,"开车")
}
},
})
</script>
总结:
-
vue会检测data中多有层次的数据
-
vue如何检测对象中的数据
通过setter实现监视,且要在new Vue时就传入要检测的数据
-
对象中后追加的属性,Vue默认不做响应式处理
-
如需给后添加的属性做响应式处理,要使用一下API
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
-
-
如何检测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新
- 重新解析模板,今儿更新页面
-
在Vue修改数组中的某个元素一定要使用如下方法
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
特别注意:Vue.set(),vm.$set()不能给vm或者vm的跟数据对象添加属性!
14.收集表单数据
<div id="rood">
账号:<input type="text" v-model = 'accont'><br>
密码:<input type="password" v-model = 'password'><br>
性别:
男<input type="radio" name="sex" v-model = 'sex' value="male">
女<input type="radio" name="sex" v-model = 'sex' value="female"><br>
爱好:
<input type="checkbox" v-mosel = "hobby" value="study">学习
<input type="checkbox" v-mosel = "hobby" value="game">打游戏
<input type="checkbox" v-mosel = "hobby" value="wang">王者<br>
所属学校:
<select name="" id="">
<option value="mo">请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
</select><br>
其他信息:
<textarea name="" id="" cols="30" rows="10"></textarea><br>
<input type="checkbox">阅读并接受<a href="#">《用户协议》</a>
<button>提交</button>
</div>
<script>
Vue.config.devtools = true;
let vm = new Vue({
el:"#rood",
data:{
accont:"",
password:"",
sex:"male",
hobby:[],
},
})
</script>
15.过滤器
定义:对咬显示的数据进行特定的格式化后在显示(适用于一些简单的逻辑处理)
语法:
- 注册过滤器:Vue.filter(name,callback)或者new Vue(filter:{})
- 使用过滤器:{{xxx | 过滤器名}}或者:x=“xxx | 过滤器名”
备注:
- 过滤器也可以接受额外参数,多个过滤器也可以串联
- 并没有改变原本数据,是产生新的数据
<div id="rood">
<h2>显示格式化的时间</h2>
<h3>现在是:{{fmtime}}</h3>
<h3>时间是:{{time | timeFormat('YYYY年MM月DD日 HH:mm:ss')}}</h2>
<h3>时间是:{{time | timeFormat('YYYY年MM月DD日')}}</h2>
</div>
<script>
Vue.config.devtools = true;
let vm = new Vue({
el:"#rood",
data:{
time:1666789411068
},
computed:{
fmtime(){
return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
}
},
filters:{
timeFormat(value,str='YYYY年MM月DD日 HH:mm:ss'){
return dayjs(value).format(str)
}
}
})
</script>
15.指令
- v-bind:单向绑定解析表达式
- v-model:双向数据绑定
- v-for:遍历数组、对象、字符串
- v-on:绑定事件监听,可以简写为@
- v-if:条件渲染(动态控制节点是否存在)
- v-else:条件渲染(动态控制节点是否存在)
- e-show:条件渲染(动态控制节点是否展示)
t-text:
- 想起所在的节点中渲染文本内容
- 与插值语法的区别:v-text会替换条节点中的内容,{{xxx}}不会
v-html:
-
作用:向指定节点中渲染包含html结构的内容
-
与差值语法的区别:
- v-html会替换掉节点中多有的内容,容易导致xss攻击
- v-html可以识别html结构
-
严重注意:v-html有安全问题
- 在网站主动渲染任意html是非常危险的,容易导致xss攻击
- 一定要在可信的内容上使用v-html,永远不要在用户提交的内容上
v-cloak(没有值):
- 本质是一个特殊属性,Vue实例创建完毕冰接管容器后,会删掉v-cloak属性
- 使用css配考核v-cloak可以解决王叔慢时页面展示出{{xxx}}的问题
v-once:
- v-once所在节点初次动态渲染之后,就视为静态内容了
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
v-pre:
- 可以跳过其所在节点的编译过程
- 可以利用他跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
自拟定指令:
-
定义语法
- 局部指令:
- 全局指令:
Vue.directives("big",function(){ }) directives:{ big(element,binding){ element.innerText = binding.value*10 }, fbind:{ bind(element,binding){ element.value = binding.value }, inserted(element,binding){ element.focus() }, update(element,binding){ element.value = binding.value element.focus() } } }
-
配置对象中常用的三个问题:
- bind:指令与元素成功绑定时调用
- inserted:指定所在元素被插入页面时调用
- update:指令所在模板结构重新被解析时调用
-
备注:
- 指令定义时不能加v-,但是使用的时候要加v-
- 指令名如果是多个单词,使用时多个单词之间要用“-”隔开,不要用驼峰命名法。
16.生命周期
- 定义:生命周期又称生命周期函数,生命周期回调函数,生命周期钩子
- 是什么:Vue在关键时刻帮我们调用一些特殊名称的函数
- 生命周期周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的this指向的是vm或者组件实例对象
总共八个函数,四对
将要创建:调用beforeCrea函数
创建完毕:调用create函数
将要挂载:调用beforeMount函数
挂载完毕:调用mounted函数(重要钩子)
将要更新:调用beforeUpdate函数
更新完毕:调用update函数
将要销毁:调用beforeDestroy函数(重要钩子)
销毁完成:调用destroyed函数
常用的生命周期钩子:
- mounted:发送ajax请求,启动定时器,绑定自定义事件,订阅消息(初始化操作)
- beforDestroy:清楚定时器,解绑自定义事件,取消订阅事件(收尾工作)
关于销毁Vue实例:
- 销毁后借助Vue开发工具看不到任何信息
- 销毁后自定义事件会失效,但原生DOM事件已然有效
- 一般不会在beforDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
17.组件
事件应用中局部功能代码和资源的集合
组件一定不能写配置项,因为最终所有组件都要被一个vm管理,由vm决定服务谁
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
二、注册组件
三、使用组件(写组件标签)
一、定义组件
const student = Vue.extend({
template: `
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>`,
data() {
return {
studentName: "zhangsan",
age: 18
}
},
})
const hello = Vue.extend({
template: `
<h2>你好</h2>
`,
data() {
return {
studentName: "zhangsan",
age: 18
}
},
})
Vue.component("hello",hello)
let vm1 = new Vue({
el: "#rood",
components: {
xuexiao: school,
xuesheng: student
},
methods: {
}
})
- el不要写,最终所有组件都要经过一个vm管理,由vm中的el决定服务那个容器
- data必须写成函数,避免组件被复用时,数据存在引用关系
备注:使用template可以配置组件结构
二、如何注册组件
- 局部注册,考new Vue的时候传入components选项
- 全局注册,靠Vue.component(“组件名”,组件)
三、编写组件标签
直接使用组件名
几个注意点:
-
关于组件名
一个单词组成:
- 第一种写法(首字母小写)
- 第二种写法(首字母大写)
多个单词组成:
- 第一种写法(kebab-case命名)
- 第二种写法(CamelCase命名)
备注:
- 组件名尽可能回避HTML中已有的元素名,大小写都不要,例如:h1,h2
- 可以使用name配置项指定组件在开发者工具中呈现的名字
-
关于组件标签:
- 第一种写法:
- 第二种写法:
备注:不适用脚手架时,会导致后续组件不能渲染
-
一个简写方式:
const school = Vue.extend(options)可以简写为const school = options
关于VueComponent:
-
school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
-
我们只需要写或者,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
-
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent
-
关于this的指向问题:
-
组件配置中:
data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均是VueComponent实例对象
-
new Vue()配置中:
data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均为Vue实例对象
-
-
VueComponent的实例对象,以后简称vc(也可以称为:组件实例对象)
Vue的实例对象,以后简称vm
Vue中的一个重要的内置关系:VueComponent.prototye._proto_=Vue.prototye
为什么要有这个关系,让组件实例对象vc可以访问到Vue原型上的属性、方法
18.单文件组件
render函数
-
vue.js和vue.runtime.xxx.js的区别
- Vue.js是完整版的Vue,包含核心功能加模板解析器
- vue.runtime.xxx.js是运行版的vue,只包含核心功能,没有模板解析器
-
因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置型,需要使用render函数接受收到的createElement函数去指定其具体内容
ref
- 被用来给元素或者子组件注册引用信息(id替代)
- 应用在html标签上获取的是真实的DOM元素,应用在组件上是组件的实例对象
- 使用方式:
<h2 ref="title"></h2>
<button @click="show">点我显示名字</button>
<School ref="sho"></School>
export default {
name:"App",
components:{
School
},
methods: {
show(){
console.log(this.$refs.title);//真实DOM元素
console.log(this.$refs.sho);//School组件的实例对象
}
},
}
props配置项
功能:让组件接受外部传过来的数据
-
传递数据:
-
接受数据(三种方法)
// props:['name','age','sex']//检点接收 props:{ name:String, age:Number, sex:String } props:{ name:{ type:String, required:true }, age:{ type:Number, default:99 }, sex:{ type:String, required:true } }
备注:props是只读的,Vue底层会检测你对props的修改,如果进行了修改就会发出警告,若是业务确实需求改参数,那么要用props的内容到data中一份,然后去data中修改数据
mixin
功能:可以把多个组件公用的配置提取成一个混入对象
使用方式:
- 第一步定义混合
- 第二如使用混合
- 全局使用混入:Vue.mixin(xxx)
- 局部混入:mixin[‘xxx’]
插件
功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
定义插件:
export default{
install(Vue){
Vue.filter("muSlice", function () {
return values.slice(0,4)
})
}
}
使用插件:Vue.use()
19.组件化代码流程
-
实现静态组件:抽取组件,使用组件实现静态页面效果
-
展示动态数据:
- 数据类型,名称是什么
- 数据保存在哪个组件中
-
交互——从绑定事件监听开始
-
组件化的编码流程:
-
拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
-
实现动态组件:考虑好数据的存放位置,数据是一个组件再用,还是一些组件再用
- 一个组件在用:放在组件自身即可
- 一些组件在用:放在他们共同的父组件上(状态提升)
-
实现交互:从绑定事件开始
-
-
props适用于:
- 父组件==》子组件通信
- 子组件==》父组件通信(要求父先给子一个函数)
-
使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的
-
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做
20.组件的自定义事件
-
一种组件之间通信的方式:适用于子组件===》父组件
-
使用场景:A是父组件,B是子组件,b想给a传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)
-
绑定自定义事件:
-
第一种方式:在父组件中:<Demo @事件名=“text”/>或者<Demo v-on:事件名=“text”/>
-
第二种方式:在父组件中:
mouted(){
this. r e f s . x x x . refs.xxx. refs.xxx.on(‘事件名’,this.text)
}
-
若想让自定义事件只触发一次,需要使用once修饰
-
-
触发自定义事件:
this.$emit(“事件名”,数据)
-
解绑自定义事件:
this.$off(“事件名”)
-
组件上可以绑定原生DOM事件,需要使用native修饰
-
注意:通过this. r e f s . x x x . refs.xxx. refs.xxx.on(‘事件名’,this.text)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题
21.全局事件总线
-
任意组件之间通信
-
安装全局事件总线:
new Vue({
// 下面这行代码,完成了一个功能:将App组件放入容器中
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this//安装全局事件总线
}
}).$mount('#app')
-
使用事件总线:
- 接受数据,A组件想接受数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
methods:{ demo(data){ } } mouted(){ this.$bus.$on("xxx",demo) }
- 提供数据:this. b u s . bus. bus.emit(“xxx”,数据)
-
最好在beforDestroy钩子中,用$off解绑当前组件所用到的事件
21.路由
-
什么是路由?
- 一个路由就是一组对应关系(key-value)
- key为路径,value可能是function或者component
-
路由分类
- 后端路由:
- 理解:value是function,用于处理客户端提交的请求
- 工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据
- 前端路由:
- 理解:value是component,用于展示页面内容
- 工作过程:当浏览器的路径改变时,对应的组件就会显示
- 后端路由:
router-link:绑定路由
router-viem:路由视图
几个注意点:
- 路由组件通常放在pages文件中,一般组件通常放在components文件夹中
- 通过切换“隐藏”的路由组件,默认是被销毁的,需要的时候再去挂载
- 每个组件都有自己的$route,里面存储自己的路由信息
- 整个应用只有一个router,可以通过组件的$router属性获取
嵌套路由:
使用children进行嵌套
query传参:
query:{
id:m.id
title:m.title
}
在router-link标签中写
props传参
第一种:
props:{a:1,b:hello}
第二种:
props:true 为布尔值,若布尔值为真,就会吧该路由组件接收到的所有params参数,以props的形式穿给Detail组件
第三种写法:
props($route){
retern{a: r o u t e . q u e r y . i d , b : route.query.id,b: route.query.id,b:route.b}
}
router-linkde的replace属性
- 作用:公职路由器跳转时候操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换掉当前的记录路由跳转的时候默认为push
- 在router-link标签中添加replace属性即可开启
缓存路由组件:
- 作用:让步展示的路由组件保持挂载,不被销毁
- 具体编码
需保持挂载的内容