目录
单文件组件(下面内容都是基于单文件组件,需要使用角手架创建项目)
简介
标签属性:
指令:v-if、v-for等
属性:data、components 等
组件:单组件、多组件
组件通信:ref、自定义事件、全局数据总线等
数据处理:vux、服务器代理、路由等
一、创建Vue对象
1、想让Vue工作,就必须创建一个Vue实例 2、Vue中el属性通过css选择器的方式绑定一个div容器 3、div容器里的代码被称为:vue模板 4、data属性为需要替换div容器中的数据 5、一个Vue对象只能对应一个div容器 6、注意区分js表达式 和js代码(语句) : {{xx}} 中xxx要写js表达式,且xxx会自动读取Vue data 中的key :value 7、一旦datd中的数据发送了改变,那么页面中用到该数据的地方也会自动改变
const x=new Vue({
el: '#root', //用于指定Vue实例为哪个容器服务,值通常为css选择器字符串
data:{ //dataz中用于存储数据,数据供el所指定的容器去使用
name:'Vue'
}
});
二、Vue模板语法
1、 插值语法
用于解析标签体内容 {{xx}} 标签体内容 获取xx的内容,xx可以为Vue内的全部属性不局限于data
<h1>Hello,插值{{name}}</h1>
2、指令语法
用于解析标签(包括:标签属性、标签体内容、绑定事件...)
v-bind: 绑定标签属性 ;可以简写成 :冒号
<a v-bind:href="url"> 点我跳转</a>
简写成冒号
<a :href="url"> 点我跳转</a>
js api
xx.toUpperCase() 大写 Date.now()时间戳
三、数据绑定
1、 单向数据绑定 v-bind 标签只能从data中提取数据
<span>单向数据绑定:</span><input type="text" v-bind:value="name">
2、双向绑定 v-model 标签不仅能从data提取数据,再数据发生改变时data中数据也会被修改
(1)、双向绑定一般都应用再表单元素上(input、select 等) (2)、 v-model:value 可以简写为 v-model 因为 v-model 默认绑定的就是value值
<span>双向数据绑定:</span><input type="text" v-model:value="name">
简写成
<span>双向数据绑定:</span><input type="text" v-model="name">
四、 el与data的写法
1、 el 两种写法
直接绑定 el:'#root' 不使用el 通过创建Vue的实例对象,调用$mount()方法 vm.$mount("#root");
2、data 两种写法
(1)对象式
data:{
name:'jack',
url:'www.baidu.com',
Name:'蝙蝠侠'
}
(2)方法式
写成方法的形式,返回对象
单模块组件data只能写成方法式
data:function (){
return {
name:'jack',
url:'www.baidu.com',
Name:'蝙蝠侠'
}
}
//简写
data(){
return {
name:'jack',
url:'www.baidu.com',
Name:'蝙蝠侠'
}
}
五、事件处理
1、使用v-on:xxx 或 @ xxx 绑定事件,其中xxx是事件名字: 2、事件的回调函数需要配置在Vue对象的methods 对象中。 3、methods中配置的函数不用使用 ()=>{} 函数,否则this就不是vm 4、methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象 5、传参数 @click="demo" ,默认传参数 ($event) 即: @click="demo($event)";
自定义传参数 @click="demo($event,4)"; 不使用$event: @click="demo(4)"
<button v-on:click="showInfo">提示信息(不传参)</button>
<button @click="showInfo2($event,66)">提示信息(传参)</button>
const vm=new Vue({
el:'.root',
data(){
return {
name:'jack',
address:'蝙蝠侠'
}
},
methods:{
showInfo (event){ //对象里写方法: 方法名()
console.log(event) //此处this是vm
/**
* event.target 当前标签元素
*
*/
},
showInfo2 (event,a){ //对象里写方法: 方法名()
console.log(event,a) //此处this是vm
}
}
});
v-on: v-on:click methods 事件响应方法
六、事件修饰符
@click.prevent
修饰符可以连续写: @click.prevent.stop
Vue中的事件修饰符: 1、prevent: 阻止默认事件(常用); 2、stop: 阻止事件冒泡(常用) 3、once:事件只触发一次(常用) 4、capture: 使用事件的捕获模式 冒泡时候事件比内层先执行 5、self: 只有event.target是当前的操作元素才触发事件(点击的是自己才会触发) 6、passive: 事件的默认行为立即执行,无需等待事件回调执行完毕
--prevent: 阻止默认事件 --
<a href="www.baidu.com" @click.prevent="showInfo">点击</a>
-- 事件冒泡: 由于button和div有层级 关系 ,点击button 相当于也点击了div--
-- stop: 阻止事件传递(冒泡)--
<div @click="showInfo">
<button @click.stop="showInfo"> 冒泡</button>
</div>
-- once: 事件只触发一次--
<button @click.once="showInfo"> 只执行一次</button>
!-- 点击button 虽然事件会冒泡到div 但event.target 依旧是button--
-- self: event.target是当前元素时候才会触发事件 --
<div @click.self="showInfo">
<button @click="showInfo"> 冒泡</button>
</div>
补充事件处理后面不仅仅可以写方法名字,还可以直接写表达式(处理过程)
<button @click="numbers.a++">点我让a++</button>
七、键盘事件
@keyup.enter 多个键盘组合支持连用 : @keyup.enter.up
1、通过键值处理
处理:event.keyCode 获取按下键盘的键值
placeholder :默认提示信息
<input type="text" :placeholder="msg" @keyup="showInfo2">
2、通过匹配键对 (只有部分键)(推荐使用)
Vue键盘别名 @click.enter 回车 delete=> 删除 退格 esc =>退出 space =>空格 tab =>换行 up =>上 down =>下 left =>左 right =>右
<input type="text" :placeholder="msg" @keyup.enter="showInfo2">
3、系统修饰键(用法特殊):ctrl、alt、shift、meta
(1)、配合keyup使用 :按下修饰符键的同时,再按下其他键,事件才触发 (2)、配合keydown使用:正常触发事件
4、也可以使用keyCode去指定具体键值(不推荐)
@keyup.13
<input type="text" :placeholder="msg" @keyup.13="showInfo2">
5、Vue.config.keyCodes 自定义键名字 = 键值 可以去自定义键盘名
Vue.config.keyCodes.En =12;
八、methods属性
编写事件的回调
placeholder :默认提示信息
<input type="text" :placeholder="msg" @keyup="showInfo2">
methods:{
showInfo2(event){
//即使没有传参数也能接受到一个event的dom
}
hello(){
return '你好'
}
}
模板中使用时候要加上 () 括号 {{xx()}}
<h2>{{hello()}}</h2>
九、计算属性(computed)
箭头函数(lambda): 没有自己的this this会指向外层
计算属性依赖返回值
(1)、计算属性的全写
语言模板调用{{xx}}
computed:{
xx:{
get(){},
set(value){}
}
}
1、定义:要用的属性不存在,要通过已有的属性计算得来 2、原理:底层借助了Object.defineproperty 方法提供的getter和seter方法 3、get() 方法 (1)、拥有缓存,初次读取时会执行一次 (2)、 重复读取数据之后调用缓存中的数据不会执行get方法 ,当数据被改变再次读取时才会调 用, set()方法 当数据被修改时候调用 4、计算属性最终会出现在vn身上 使用直接可以调用 模板使用{{xx}},只有methods里的方法放入才要加括号{{xx()}} 另外 ="xx" xx内所有都不用加括号 5、优势:与methods实现相比,内部有缓存(复用机制),效率高,调试方便
(2)、计算属性的简写:对于只读不改的计算属性(常用,依赖返回值)
computed:{
xx(){
return x;
}
}
直接把当前计算属性写成方法 直接写一个方法对应get方法
computed:{
TfullName(){
console.log('get被调用');
return this.firstName+'-'+this.lastName;
}
}
十、监视属性(watch)
watch:捕捉data的的数据是否被修改 监视对象、数组时候最好最好开启深度监视(需要开启深度监视再写全写形式) 相关属性 immediate:true, //初始化调用 deep:true, //深度监控开启 handler()或handler(newValue,oldValue) //当前监控属性被修改时候调用,会获得它的新旧值 1、当被监视的属性变化时,回调函数handler(newValue,oldValue)方法自动调用,进行相关操作 2、监视的属性必须存在,才能进行监视 3、监视的两种写法 通过watch属性配置 通过vm.$watch配置监视 handler(newValue,oldValue)方法:当xx被修改时候执行; immediate:true 初始化时候就让handler 调用一下,默认为false
(1)、全写形式:
watch:{
XX:{
//初始化时候就让handler 调用一下,默认为false
immediate:true,
//handler 当data中的XX被修改时候执行,会获取到xx的被修改后的值和原来的值
handler(newValue,oldValue){
}
}
(2)、简写写法:
当不需要开启深度监视时候
watch:{
XX(newValue,oldValue){
//xx被修改
}
}
(3)、另一种写在 ,通过vm使用
vm.$watch('XX', {
immediate: true,
handler(newValue, oldValue) {}
})
(4)、深度监视: (1)、Vue中watch默认不检测对象内部值的改变(一层) (2)、配置deep:true 可以检测对象内部值改变(多层)
监视对象中的单个属性
//监测多级,此时key不能简写,只能写成字符串的形式
'numbers.a':{
handler(){
console.log('a改变')
}
},
直接监控最大层需要开启深度监控deep:true ,它默认是false
numbers: {
deep:true,
handler(){
console.log('numbers被改变');
}
}
(5)、 computed(计算属性) 和watch(监视属性)之间的区别:
1、computed(计算属性)能完成的功能,watch(监视属性)都可以完成 2、watch(监视属性)能完成的功能,computed(计算属性)不一定能完成,例如 computed 依赖返回值 两个小原则:所有被Vue管理的函数,最后写成普通函数,这样this的指向才是vm或实例对象 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等)最好写成箭头函数,这样this的指向才是vm或实例对象
十一、Vue数据检测原理
1、Vue会监视data对象中的数据。 通过setter实现监视,且要在new Vue 时就已经创建了要监视的数据 (1)、对象中后追加的属性,Vue默认不做响应式处理 (2)、如需给后添加的属性做响应式,需要使用Vue 的API
Vue.set(属性,需要添加的属性或索引,value) vm.$set(属性,需要添加的属性或索引,value) 例如 this.$set(this.student,1,'{name:'小红',age:33}'); Vue.set(this.st,'sex','男'); this.$set(this.st,'sex','男'); 注意:Vue.set() 和vm.$set() 不能给vm 或vm的根数据添加属性
2、监测数组中的数据 通过包裹数组更新元素的方法实现 (1)、调用原生对应的方法对数组进行更新 (2)、重新解析模板,进行更新页面
3、修改数组中的某个元素 (1)、使用数组api:push()、pop()、shift()、unshift()、splice()、sort()、reverse() (2)、Vue.set() 或 vm.$set()
注意 不能通过数组索引直接赋值修改 var student=[{name:'小王',age:13},{name:'小明',age:34}] student[0]={name:'小红',age:33} 错误vue监视不到 student[0].name='小红' 正确 Vue可以监视到 添加或修改 索引 this.$set(this.student,1,'{name:'小红',age:33}');
十二、绑定clss样式
(1)、绑定class样式 绑定class样式 字符串写法,适用于样式的类名不确定,需要动态绑定
<div id="root" class="root2" :class="mood" @click="Onck">
mood: 'root'
绑定class样式 classAll是存储class名的数组,适用于样式的类名不确定,样式不确定需要动态绑定
<div id="root" class="root2" :class="classAll" @click="Onck">
classAll:['root','root2']
绑定class样式 数组写法 适用于:要绑定的样式个数确定,名字也确定,但要动态决定用不用
<div id="root" class="root2" :class="classObj" @click="Onck">
这里root5 不能瞎写 要对应有css的样式(data中) classObj:{ root5: true, root3: false }
(2)、绑定style样式
<div id="root" class="root2" :style="classObj" @click="Onck">
里面key为css属性驼峰命名
classObj{ fontSize: '40px', color: 'red' }
十三、条件渲染
1、v-if
写法: (1)、v-if="表达式" (2)、v-else-if="表达式" (3)、v-else="表达式" 适用于:切换频率较低的场景。 特点:不展示的DOM元素直接被移除 注意:v-if可以和:v-else-if、v-else 一起使用但要求结构不能被”打断“
例如
<h2 v-if="n===2"> 欢迎来到if{name}}</h2>
<h2 v-else-if="n===2"> 欢迎来到v-else-if{name}}</h2>
<h2 v-else> 欢迎来到v-else{name}}</h2>
<template></template> 无属性模板 作用和div类似,它被解析会消失不见
只能与v-if配合使用不能和v-show
2、 v-show
写法:v-show="表达式" 适用于:切换频率较高的场景 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
<h2 v-show="n===1"> 欢迎来到show{{name}}</h2>
备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到
十四、列表渲染
v-for指令 1、用于展示列表数据 2、语法:v-for="(itm,index) in xxx" :key="yyy" 。 (in可以换成of,效果一致) 或 v-for="itm in xxx" :key="itm.id" 3、可以遍历:数组、对象、字符串(用得很少)、指定次数(用得很少)
(1)遍历数组 persons:[{name:'s',age:'23'},{name:'b',age:'13'}]
<ul>
遍历数组 数据 索引
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}--{{index}}
</li>
</ul>
(2)遍历对象 car:{name:'as',age:14}
<ul> value key
<li v-for="(value,k) in car" :key="k" >
{{value}}--{{k}}
</li>
</ul>
(3)字符串 str:'heel'
<ul>
<li v-for="(value,index) in str" :key="index" >
{{value}}--{{index}}
</li>
</ul>
(4)、遍历指定次数
<ul>
<li v-for="(number,index) in 5" :key="index" >
{{number}}--{{index}}
</li>
</ul>
(5)、备注 vue中的key有扫描作用? 1、 用index作为key可能会引发的问题 若对数据进行:逆序添加、逆序删除等破坏顺序的操作 会使虚拟DOM对比出现问题 是页面排布发送变化(组件对应出现问题) 2、如何选择key (1)、最后使用数据的唯一表示作为key(数据id等)比如:id,手机号、身份证号、学号等 (2)、如果不存在对数据的逆序添加、逆序删除等破环顺序的操作,仅仅用于列表渲染展示 使用index作为key是没有问题的
十五、列表过滤、排序
(1)、列表过滤 使用数组的arr.filter对数组过滤(根据箭头函数返回值来确定当前元素是否需要保留) str.indexOf 判断字符串中是否有子字符串
例子 两个实现
const vm=new Vue({
el:'#root',
data:{
fliipersons:[],
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:13,sex:'女'},
{id:'002',name:'周东雨',age:17,sex:'女'},
{id:'003',name:'周杰伦',age:19,sex:'男'},
{id:'004',name:'温赵伦',age:16,sex:'男'}
],
},
watch: {
//当关键字keyWord改变时候对数组进行筛选
keyWord: {
immediate:true,
handler(val) {
//filter数组过滤 根据条件数据过滤
this.fliipersons = this.persons.filter((p) => {
return p.name.indexOf(val) !== -1;
})
}
}
},
computed:{
//计算属性 根据keyWord计算出改变后结果
fillPerons(){
//返回删选结果
return this.persons.filter((p)=>{
//根据关键字筛选
return p.name.indexOf(this.keyWord)!==-1;
})
}
}
})
(2)、 列表排序 通过计算属性实现 在原来数组已经筛选的情况下进行排序 调用arr.sort 对数组进行修改原数组进行排序(根据箭头函数前后数据比对大小的结果交换顺序)
computed:{
//计算属性 根据keyWord计算出改变后结果
fillPerons(){
//返回删选结果
const arr=this.persons.filter((p)=>{
//根据关键字筛选
return p.name.indexOf(this.keyWord)!==-1;
});
if(this.sortType){
//arr.sort改变原来数组 对原来数组进行排序
arr.sort((p1,p2)=>{
return this.sortType===1? p2.age-p1.age:p1.age-p2.age;
})
};
return arr;
},
}
十六、收集表单数据、
(1) 账号密码输入框
<input type="number" id="dome" v-model="userInfo.account">
v-model设置为空字符串 收集的是value的值,用户输入的就是value值
(2)、单选框
<input type="radio" name="sex" value="man" v-model="userInfo.sex" >男
<input type="radio" name="sex" value="women" v-model="userInfo.sex" >女
v-model设置为空字符串,v-model收集的checked值,标签需要设置value,哪个value被选中,v-model就为哪个value
v-model初始化设置了值,对应的数据单选框就会被选中
(3)、多选框
选项只有一个
<input type="checkbox" v-model="userInfo.ge">
v-model设置为空字符串 ,v-model对应的数据是布尔值 ,标签不用设置value 选中时候v-model为true
多个选项
<input type="checkbox" name='haobi'v-model="userInfo.haobi" value="xuex">学习
<input type="checkbox" name='haobi'v-model="userInfo.haobi" value="game">打游戏
<input type="checkbox" name='haobi'v-model="userInfo.haobi" value="eat">吃饭
v-model设置为空数组 哪个被选中,v-model就会添加对应value
v-model初始化数组设置了值,对应的数据单选框就会被选中
(4)、下拉框
<select v-model="userInfo.seter">
<option>请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="liaoning">辽宁</option>
</select>
v-model设置为空字符串,标签需要设置value,哪个value被选中,v-model就为哪个value
v-model初始化设置了值,对应的数据就是初始选中的数据
(5)、 输入控制
<input type="number" id="dome" v-model.number="userInfo.account">
v-model.number
和 type="number"组合使用代表:只能输入数字类型,接受数据也是数字类型
v-model.lazy:懒加载,失去当前焦点才接受数据
v-model.trim: 接收数据时候自动去掉首尾空格
十七、过滤器(filters)
定义:对要显示的数据进行特定格式化操作后再显示(适用于简单逻辑的处理) {{参数 | 过滤器方法名(参数)}} :把当前值作为参数传递到过滤器中进行处理,整体为过滤器方法返回的结果 {{参数 | 过滤器方法名(参数) | 过滤器}}:把当前值作为参数传递到过滤器中进行处理再把返回值传递到第二个过滤器进行处理,整体为第二个过滤器方法返回的结果
语法: 本质上还是方法
<h3>现在是:{{time | timeFormater}}</h3>
过滤器支持串联
<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
1、注册过滤器
局部过滤器 定义在vc 中
filters:{
方法名(参数1,参数2){
return
}
}
filters:{
timeFormater(value,str="YYYY-MM-DD HH:mm:ss"){
console.log("value值"+value);
return dayjs(value).format(str);
}
}
全局过滤器 全局配置
Vue.filter('方法名',function (value){
return;
})
//全局过滤器
Vue.filter('mySlice',function (value){
return value.slice(0,4);
})
备注: 过滤器可以接收额外参数、多个过滤器可以串联 并没有改边原本的数据,是产生新的对应的数据
十八、Vue2内置模板指令
v-bind:单向绑定 v-model:双向绑定 v-for:循环遍历 v-on:事件绑定 v-if:模板渲染 v-else:模板渲染 v-show:模板渲染
(1)、v-text:
作用 完全替换标签文本内容 与插值语法区别:v-text会替换节点内容,{{xx}}不会,没有插值语法灵活,都不支持html解析
<div v-text="msg"></div>
(2)、v-html
作用和v-text一致,但v-html支持html标签结构解析
<div v-html="msg"></div>
处理不好会引发计算机安全问题 document.cookie
(3)、v-cloak(无值) 可以用来做页面加载
1、本质是一个特殊属性,Vue实例创建完毕并且接管容器后,会移除v-cloak(只是移除v-cloak,不是移除对应的标签) 2、配合css使用可以解决网速慢时候页面展示出{{xx}}的问题,也可以设计加载动画
css: [v-cloak]{ }
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
(4)、v-once(无值) v-once所在节点在初次动态渲染后,就视为静态内容了 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
<h2 v-once>初始化n值是:{{n}}</h2>
(5)、v-pre(无值)
跳过其他所在节点的编译过程,让它展现当前节点原来的面貌 可以利用它跳过:没有使用插值语法的节点,会加快编译
十九、自定义指令(directives)
<span v-big="n"></span>
(1)局部指令
对象形式
directives:{指令名:配置对象} 配置对象里面有三个固定方法 对象形式配置中的三个方法: bind(element,binding) :指令与元素成功绑定时候调用 inserted(element,binding) :指令所在元素被插入页面时调用 update(element,binding) : 指令所在模板结构被重新解析时候调用
方法形式
directive:{
指令名字(element,binding){
}
}
// 自动传入参数:element=> 标签dom对象
// binding=> 标签中自定义指令 等号右边的数据对象
例子:
directives:{
//方法形式
//big函数调用:1、指令与与元素成功绑定时(一上)。2、指令所在的模板被重新解析时
big (element,binding){
console.log('输出')
element.innerText=binding.value*10;
},
//对象形式 能执行更加复杂的操作 三个属性方法是固定的
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus();//获取焦点
console.log('inserted')
},
//指令所在的模板被重新解析时(刷新或有按钮点击)
update(element,binding){
element.focus();
console.log('update')
}
}
}
(2)、全局指令
方法形式 Vue.directive('指令名字',function (element,binding))
对象形式
Vue.directive('指令名字',{
bind(element,binding){}, //指令与元素成功绑定时候调用
inserted(element,binding){}, //指令所在元素被插入页面时调用
update(element,binding){} //指令所在模板结构被重新解析时候调用
})
例如:
//方法形式
Vue.directive('big', function (element,binding){
console.log('输出')
element.innerText=binding.value*10;
}),
//对象形式
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value=binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){z
element.focus();//获取焦点
console.log('inserted')
},
//指令所在的模板被重新解析时(刷新或有按钮点击)
update(element,binding){
// element.focus();
console.log('update')
}
})
备注:指令方法定义时不加v-,但使用时要加v- 指令名如果是多个单词,要使用kebab-case(user-name)命名方式,不用cameCase命名
二十、生命周期(生命周期钩子)
methods 里面创建定时器要注意定时器的释放 否则每执行一次方法定时器都会被创建 Vue在关键时刻帮我们调用的一些特殊名称的函数 生命周期回调函数、生命周期函数、生命周期钩子 生命周期函数的名字不能更改,但函数的具体内容是直接可以编写的 生命周期函数的this是vm 或组件实例对象
(1)、 mounted(){}:
发送ajax请求、启动定时器、绑定自定义事件、订阅消息等(初始化操作) Vue完成模板的解析并把初始真实的DOM元素放入页面后(挂载完毕)调用mounted 只在打开页面时候自动调用一次
(2)、beforeDestroy
清除定时器、解绑自定义操作、取消订阅等(收尾工作)
(3)、钩子
钩子: 将要创建 ==> 调用beforeCreate 函数 创建完毕==> 调用created 函数 将要挂载==> 调用beforeMount 函数 重要 挂载完毕 ==> 调用mounted 函数 ===> 重要钩子 将要更新 ==> 调用beforeUpdate 函数 更新完毕 ==> 调用updated 函数 重要 将要销毁 ==> 调用beforeDestroy 函数 ===>重要钩子 销毁完毕 ==> 调用destroyed 函数
二十一、Vue组件化编程
下文都是基于组件化编程
非单文件组件:一个文件中包含有n个组件 单文件组件:一个文件中只包含一个组件
非单文件组件
Vue.extend 步骤: 定义组件(创建组件) 注册组件 使用组件(写组件标签)
(1)、定义组件
使用 Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样。 区别: 1、el不要写 2、data必须写成函数 3、使用template可以配置组件html结构
//创建student组件
const student=Vue.extend({
template:`
<div>
<h2> 学生名称:{{studentName}}</h2>
<h2>学生地址:{{age}}</h2>
</div>
`,
data(){
return {
studentName:'小伟',
age:18
}
}
});
(2)、 注册组件
局部注册
靠new Vue的时候注入components选项
new Vue({
el:'#root',
//注册组件 (局部注册)
components:{
school:school,
student:student
}
})
全局注册:
靠Vue.component('组件名',组件)
Vue.component('hellox',hellox);
(3)、编写组件标签
直接使用key
<school></school>
组件命名注意 1、不要和html标签同名 2、可以kebab-case命名:my-school 3、CameCase命名: MySchool(需要使用Vue脚手架) 尽量使用小写 4、注册的名字和使用名字一致,无关大小写,使用单闭合标签也可以(脚手架环境) 5、在创建组件的时候内部设置name属性,难么Vue开发者工具中呈现的就是设置的name
简写方式: const school=Vue.extend({}) 可以简写成 const school={}
(4)、 组件的嵌套 子组件必须先定义 在父组件的template使用子组件
(5)、VueComponent(VC) school定义的组件本质是一个VueComponent的构造函数,是Vue.extend生成的 我们在使用标签形式<school></>school>,Vue解析时会帮我们创建school组件的实例对象,即new VueComponent(options) 特别注意: 每次调用Vue.extend. 返回的都是一个全新的VueComponent!!
school.prototype.__proto__===Vue.prototype 让组件实例对象vc可以访问到Vue原型上的属性、方法。
单文件组件(下面内容都是基于单文件组件,需要使用角手架创建项目)
#配置文件vue.config.js lintOnSave:false //关闭语法检测
二十二、ref属性
1、被用来给元素或组件引用信息(根据id获得Dom的替代者) 2、应用在html标签上获取的是真实Dom元素,应用组件标签上是组件实例对象(vc) 3、使用方式:
标签上: <h1 ref="xxx"> </h1>
组件(vc)上: <school ref="xxx"></school>
获取:this.$refs.xxx
操作dom时候建议配合nextTick 使用
二十三、props属性
功能
让组件接收外部传过来的数据 (传数据都是字符串 :xx=“12” 用冒号绑定才是Number类型, 需要传入Vue里的数据也要使用冒号来表面需要当作表达式解析 :xx="da")
传入值:
<Demo nema="xxx"/>
内容是表达式 或者是 vue中数据需要使用 v-bind解析
<Demo :nema="{{xxx}}"/>
组件中接受值
(1)、第一种方式
props['name']
(2)、第二种方式 (限制传入的数据类型)
props:{ name: Number }
(3)、第三种方式 (限制类型、限制必要性、指定默认值)
props:{ name:{ type: String //类型 required:true //必要性 default: '老王' //默认值 } }
备注:props是只读的,Vue底层会监视你对props的修改,如果进行了修改,就会发出警告 真要修改的时候可以data接收props,通过修改data来达到相同的效果 props可以传入引用数据
(4)、基于 props的组件通信 父向子传输数据 ==> 在父中通过子标签传输数据 子向父传输数据 ==> 在父中通过子标签传输父的一个方法,在子中调用该方法间接传输(方法传入子中依旧是父的方法)
在外部定义一块 可复用的代码段 export const mixin={ methods:{ showDom(){ console.log(this.$refs); } }} 引入: import {mixin} from '../mixin.js' 使用混入: mixins:[mixin,xx]
二十四、插件
用于增强Vue
定义插件
export default {
install(Vue){
console.log("@@@install");
//过滤器
Vue.filter()
//定义混入
Vue.mixin();
}
}
引入插件:import xx from "../plugins"; 使用插件 Vue.use(xx)
二十五、scoped标签属性
组件的局部css代码,可以防止样式冲突
<style scoped>
</style>
最好不要运用在App.vue中,AppVue中一般编写全局生效的,作用域局部优先
二十六、组件化编码注意点
组件化的编码流程: (1)拆分静态组件:按功能分,命名不要与html标签元素冲突 (2)考虑好数据的存放位置,数据是一个组件用还是一群组件用 一个组件用放在自生 一群组件用放在它们共同的父组件上(app) (3) 实现交互:从绑定事件开始 props试用于 父组件==>子组件通信 子组件==>父组件通信 (要求父给子组件先传递一个函数) 注意:使用V-model时要切记 v-model绑定的值不能是props传入过来的值,因为props接收的值不提倡修改 props 接收的是对象类型(数组,方法等)时候,修改属性不会报错,但不提倡修改
二十七、本地浏览器存储
存储容量大概5MB左右 window.localStorage 关闭浏览器后数据依旧保存
API:
往浏览器保存数据(setItem): window.localStorage.setItem("msg","hello"); key-value
window.localStorage.setItem("msg2",JSON.stringify(p));保存对象类型需要保存JSON格式
读取保存的数据(getItem): window.localStorage.getItem("msg2")
删除一个数据(removeItem): window.localStorage.removeItem('msg2')
删除全部(clear): window.localStorage.clear();
简写可以不写window,localStorage.getItem("msg2")
window.sessionStorage 浏览器关闭数据不会保存 API和localStorage一致
JSON JSON.stringify(X) :把对象转换成JSON字符串格式 JSON.parse(x) : 解析JSON字符串数据
二十八、组件的自定义事件
是一种组件通信的方式 适用于: 子组件==>父组件 使用场景:子组件想要给父组件传递数据 则需要在 父组件中定义子组件的自定义事件(回调函数需要在父组件中)
定义方式
<Demo @at='test'> 或者 <Demo v-on:at='test'> (推荐)
子组件中触发事件 this.$emit('at',参数) (触发事件的参数,回调函数中的参数)
父组件中还可以让 它在加载时候通过ref绑定的组件定义一个自定义事件
<Demo ref='xx'>
mounted(){
this.$refs.xx.$on('at',this.test) (事件名,回调函数)
//如果只想让自定义组件触发一次 可以使用once修饰 或者$on换成$once
}
注意 子组件中解除绑定自定义事件 this.$off('at') 子组件也可以绑定原生的DOM事件,需要使用native修饰 @click.native
二十九、全局事件总线
作用:创建中间组件,通过中间组件实现任意组件通信
原理:利用$on绑定事件 $emit触发事件
配置安装全局总线:
new Vue({
beforeCreate(){
Vue.prototype.$bus=this //把当前vm自己设置成中间件 放入Vue原型的$bus中使app和全部vc都能访问到
}
})
事件总线 绑定事件 其他子组件中 设置触发事件和回调函数
mounted(){
this.$bus.$on('xx',this.demo) //
}
最好在beforeDestroy钩子中解绑事件($off) 事件总线 触发事件 this.$bus.$emit('xx',回调函数参数)
三十、消息订阅与发布
(类似全局事件总线)使用第三方库
安装pubsub: 终端命令: npm i pubsub-js 引入:import pubsub from 'pubsub-js'
接收数据:订阅消息(使用第三方api)
mounted(){ //定于在钩子中,时刻准备接收
this.pubid=pubsub.subscribe('xxx',this.demo) //('消息名字',回调函数) 回调函数参数的一个是消息名字 第二个才是接收参数;
}
取消订阅 使用钩子 beforeDestroy 中pubsub.unbscribe(this.punbid) ;根据消息id取消订阅
发送数据:发送消息(使用第三方api) pubsub.publish('xx',数据) //('消息名字',回调函数参数)
三十一、nextTick
语法:this.$nextTick(回调函数) (一般和ref操作DOM联合使用)
作用:在下一次DOM更新结束后执行其指定的回调
什么时候用:当改变数据后,要基于更新后的新DOM进行基础操作时,要nextTick所指定的回调函数中进行
this.$nextTick(function (){
this.$refs.inputTitle.focus();
})
三十二、动画
过度动画(什么元素需要使用动画就用<transition>标签包裹)
使用<transition>
<transition-group> 多个过度元素 并且每个元素都要配置key
<transition
name='helllo'
appear 刷新时候就加载进入动画
enter-active-class=" " 显示时候的动画(配合第三方库)
leave-active-class=" " 离开时候的动画(配合第三方库)
>
</transition>
三十三、配置axios
(1)、axios
安装: nmp i axios 引入: import axios from 'axios'
例如:
methods:{
getStudengt(){
axios.get('http://localhost:8080/at/posts'
).then((response)=>{
console.log("请求成功",response.data);
}).catch((error)=>{
console.log("请求失败了",error.message);
})
}
}
例子2:路径传输参数,利用es6模板语法 ``
axios.get(
`https://api.github.com/search/users?q=${this.keyWord}`
).then((response)=>{
console.log("请求成功了",response.data.items)
pubsub.publish('xxx',{ isFirst: false, isLoading: false, list: response.data.items});
this.isshow=false
}).catch((error)=>{
console.log("请求失败了",error.message)
pubsub.publish('xxx',{ isFirst: false, isLoading: false, errMsg: error.message});
}
)
(2)、配置代理服务(devServer属性)
vue脚手架配置代理服务器 (devServer属性)(解决跨域问题) 优点:使用时候axios url地址端口号为本地端口号即可
在配置文件vue.config.js中:
方法一:
(局限性:不能配置多个、不能灵活控制是否走代理,优先匹配本地前端资源)
devServer:{
proxy:'http://localhost:3000' // (写具体服务器的地址)
}
方法二:
内部可以配置多个(devServer内的proxy属性中配置) 使用时候axios url请求地址端口号后需要加对应请求地址 /api 来区分不同的代理服务器
devServer:{
proxy:{
//请求前缀,控制是否走代理
'/api':{ //匹配所有/api开头的请求路径
target:'http://localhost:3000',
//重写路径 ,防止路径带上/atguigu
pathRewrite:{'^/api':''}, //把/api 变成空字符串
ws: true, //用于支持websocket ,默认true
changeOrigin:true //用于控制请求头的host 请求地址是否设置和外部服务器(3000)一致 默认true
}
}
}
三十四、插槽<slot>标签
往标签内部写 <cat> 插槽元素</cat> 通过<slot>标签占位 可以让父组件向子组件指定位置插入html结构,也是一种组件间通信的方式,适用与 子组件==> 父组件
1、默认插槽
父中
<cat>
<div>html结构<div/>
</cat>
子组件
<template>
<div>
<slot>无插槽内容时候的提示消息<slot>
<div/>
<template/>
2、 具名插槽(插入内容不同时候,区分显示)
使用 v-slot 属性绑定不同占位 父中
<cat>
<template v-slot:tem1>
<div>html结构<div/>
<template/>
<template v-slot:tem2>
<div>html结构2<div/>
<template/>
</cat>
子组件
通过<slot> 的name属性来区分不同占位
<template>
<div>
<slot name="tem1">无插槽内容时候的提示消息<slot>
<slot name="tem2">无插槽内容时候的提示消息<slot>
<div/>
<template/>
3、作用域插槽
可以传输参数 利用scope接收 v-bing 的数据
父主组件中(需要收到子数据来解析模板)
<cat>
<template scope="sdata" v-slot:tem1>
<div>html结构 {{sdata}}<div/>
<template/>
</cat>
子组件中(传递数据)
<template>
<div>
<slot name="tem1" :wdata="wdata">无插槽内容时候的提示消息<slot>
<div/>
<template/>
*****************************************************************************************************************
仅供学习交流