初始Vue
const vm = new Vue({ el:"#box",//el表示elements data:{ //data用于存储数据,数据仅供el里面指定的容器所用,值暂时写成对象的形式,往后可能会用到函数的形式 //el,data是这个vue实例的配置对象 name:",我是xxx" } });
单向数据绑定和双向数据绑定
<!-- <div id="box"> 单向数据绑定:<input type="text" v-bind:value="name" /> 双向数据绑定:<input type="text" v-model:value="name" /> </div> --> <!--简写--> <div id="box"> 单向数据绑定:<input type="text" :value="name" /> 双向数据绑定:<input type="text" v-model="name" /> </div> <!-- v-model 只应用在表单元素上(输入类元素 例:input selected等)-->
理解MVVM模型
<!--
MVVM模型
1.M:模型(Model):data中的数据
2.V:视图(View):模板代码
3.VM:视图模型(ViewModel):Vue实例
观察发现:
1.data中所有的属性,最后都出现在了vm身上
2.vm身上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用。
-->
defineProperty函数的认识
<script type="text/javascript"> var number = 18; var person = { name:"张三", sex:"男" } //这里的参数age的意思是,往对象person中添加一个age属性 Object.defineProperty(person,'age',{ //value:18, //如果使用这个函数添加属性的话,你修改这个属性的话,那么是不起作用的 //enumerable:true, //控制属性是否枚举(遍历),默认值是false //writable:true, //控制属性是否可以被修改,默认值是false //configurable:true //控制属性是否被删除,默认值为false //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值 get(){ console.log("有人读取了age属性了") return number; }, //当有人修改person的age属性时,set函数(setter)就会被调用,且返回值就是age的值 set(value){ console.log("有人修改了age属性了,且值是",value) number = value } }) console.log(person); </script>
非单文件组件
<!-- Vue中使用组件的三大步骤: 一、定义组件 二、注册组件 在vm中写compents:{} 三、使用组件(写组件标签)在DOM元素上面写 一、如何定义一个组件? 使用Vue.extend({})创建,其中和new Vue({})有些区别 区别如下: 1.el不要写,为什么? —— 最终所有的组件都要经过一个vm管理,由vm中的el决定服务哪个容器 2.data中必须写成函数,为什么? —— 避免组件被复用时,数据存在引用关系. 备注:使用template可以配置组件结构 二、如何注册组件 1.局部注册:靠new Vue的时候传入到components:{} 2.全部注册:靠Vue.component('组件名',组件) 几个注意点: 1.关于组件名: 一个单词组成: 第一种写法(首字母小写)school 第二种写法(首字母大写)School 多个单词组成: 第一种写法(kebab-case命名):my-school 第二种写法(CamelCase命名):MySchool(需要vue脚手架支持) 备注: (1).组件名尽可能回避HTML中已有的元素名称。例如:h2,H2等都不行。 2.关于组件标签: 第一种写法:<school></school> 第二种写法:<school> 备注:不用使用脚手架时,<school/>会导致后续组件不能渲染 3.一个简写的方式: const school = Vue.extend({}) 可简写成: const school = {} -->
非但文件组件嵌套
<body> <!-- Vue中使用组件的三大步骤: 一、定义组件 二、注册组件 三、使用组件(写组件标签) --> <div id="root"> <!--第三步,写组件标签调用--> <hello></hello> </div> <script type="text/javascript"> //要把被管理的组件放在要管理他的组件上面,把student组件归于school管理,在管理student的组件里面注册和调用student const student = Vue.extend({ template:` <div> <h4>{{name}}</h4> <h4>{{age}}</h4> </div> `, data(){ return{ name:"黄健聪", age:18 } } }) //第一步,-创建组件 const school = Vue.extend({ template:` <div> <h4>{{name}}</h4> <h4>{{address}}</h4> <student></student> </div> `, data(){ return{ name:"广东机电", address:"白云区" } }, components:{ student } }) const app = Vue.extend({ template:` <div> <school></school> </div> `, components:{ school } }) const vm = new Vue({ template:` <div> <hello></hello> <app></app> </div> `, el:"#root", //第二步,注册组件 components:{ hello, app } }) </script> </body>
过滤器
<body> <div id="root"> 计算属性:{{ftmTime}}<br/> 方法属性:{{methodsTime()}} </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ time:1646660802602 }, computed:{ ftmTime(){ return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss') } }, methods:{ methodsTime(){ //day.js 是一个轻量的处理时间和日期的 JavaScript 库,需要在终端下载 npm i dayjs return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss') } } }) </script> </body>
计算属性
姓名案例-插值语法实现
<body> <!--准备一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName" /><br/><br/> 名:<input type="text" v-model="lastName" /><br/><br/> 全名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span><!--slice():切割字符串保留三位,三位之后不再显示出来--> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ firstName:"张", lastName:"三" } }) </script> </body>
姓名案例-计算属性方法实现
<body> <!--准备一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName" /><br/><br/> 名:<input type="text" v-model="lastName" /><br/><br/> 全名:<span>{{fullName}}</span> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ firstName:"张", lastName:"三" }, computed:{ fullName:{ get(){ console.log("get被调用了"); return this.firstName + "-" + this.lastName; }, set(value){ console.log("有人在修改名字"); var arr = value.split("-"); this.firstName = arr[0]; this.lastName = arr[1]; } } } }) </script> </body>
姓名案例-methods方法实现
<body> <!--准备一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName" /><br/><br/> 名:<input type="text" v-model="lastName" /><br/><br/> 全名:<span>{{fullName()}}</span> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ firstName:"张", lastName:"三" }, methods:{ fullName(){ return this.firstName + "-" + this.lastName; } } }) </script> </body>
姓名案例-watch语法实现
<body> <!--准备一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName" /><br/><br/> 名:<input type="text" v-model="lastName" /><br/><br/> 全名:<span>{{fullName}}</span> </div> <!-- computed和watch之间的区别: 1.computed能完成的功能,watch都可以完成 2.watch能完成的功能,computed不一定能完成 。例如watch可以进行异步操作(setTimeout()定时器) 两个重要的小案例: 1.所被Vue管理的函数,最好写成普通函数,这样this的指向vm或组件实例对象。 2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等 ,Promise的回调函数),最好写成箭头函数。 --> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ firstName:"张", lastName:"三", fullName:"张-三" }, /** 1.监视属性 1.初始化要被监视的对象 2.写出要监视的对象的相关data里面要监视的对象 **/ watch:{ //1.写出要监视的对象的相关data里面要监视的对象 firstName(newValue){ //在data里面初始化要被监视的对象 this.fullName = newValue + "-" +this.lastName; }, /*setTimeout() 不被Vue所管理的回调函数,所以用箭头函数去写*/ firstName(newValue){ //在data里面初始化要被监视的对象 setTimeout(()=>{ this.fullName = newValue + "-" +this.lastName; },2000) }, lastName(newValue){ //在data里面初始化要被监视的对象 this.fullName = this.firstName + "-" +newValue; }, } }) </script> </body>
监视属性
天气案例-监视属性
<body> <div id="root"> <h3>今天天气是{{info}}</h3><!--用计算属性--> <button @click="changeWeather">切换天气</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ isHot:true }, methods:{ changeWeather(){ this.isHot = !this.isHot; } }, // watch:{ // info:{ // immediate:true,//初始化,在页面加载时监视一次,让handler()调用一次。 // handler(newValue,oldValue){//当info发生改变时调用 // console.log("info的值被修改了",newValue,oldValue) // } // } // }, computed:{ info(){ return this.isHot? '炎热' : '凉爽' }, } }) vm.$watch('info',{ immediate:true, handler(newValue,oldValue){ console.log("info的值被修改了",newValue,oldValue) } }) </script> </body>
天气案例-监视属性简写
<body> <div id="root"> <h3>今天天气是{{info}}</h3><!--用计算属性--> <button @click="changeWeather">切换天气</button><br /><br /> <h3>{{numbers.a}}</h3> <button @click="numbers.a++">点击a+1</button><br /><br /> <h3>{{numbers.b}}</h3><br /><br /> <button @click="numbers.b++">点击b+1</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ isHot:true, numbers:{ a:1, b:1 } }, methods:{ changeWeather(){ this.isHot = !this.isHot; } }, //完整写法 /* watch:{ info:{ immediate:true, handler(newValue,oldValue){ console.log("info的值被修改了",newValue,oldValue) } } },*/ /*watch简写*/ /*watch:{ info(newValue,oldValue){ console.log("info的值被修改了",newValue,oldValue ) } },*/ computed:{ info(){ return this.isHot? '炎热' : '凉爽' }, } }) /*$watch完整版*/ // vm.$watch('info',{ // immediate:true, // handler(newValue,oldValue){ // console.log("info的值被修改了",newValue,oldValue) // } // }) /*$watch简写*/ vm.$watch('info',function(newValue,oldValue){ console.log("info的值被修改了",newValue,oldValue) }) </script> </body>
天气案例-深度监视属性
<body> <div id="root"> <h3>今天天气是{{info}}</h3><!--用计算属性--> <button @click="changeWeather">切换天气</button><br /><br /> <h3>{{numbers.a}}</h3> <button @click="numbers.a++">点击a+1</button><br /><br /> <h3>{{numbers.b}}</h3><br /><br /> <button @click="numbers.b++">点击b+1</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ isHot:true, numbers:{ a:1, b:1 } }, methods:{ changeWeather(){ this.isHot = !this.isHot; } }, watch:{ info:{ immediate:true, handler(newValue,oldValue){ console.log("info的值被修改了",newValue,oldValue) } }, //因为是更深度的监视,所以要加个引号。监视多级。 //这个监视只是在点击a+的时候才会调用,要是想点击b的时候也被监视的话,同理 // 'numbers.a':{ // handler(){ // console.log("a被点击,慢慢的增大了") // } // }, //如果想在点击对象里面的每一个属性都发生监视的话,那就加个deep:true。加了之后,你点击该对象的任一属性,那么里面的属性都会被调用 numbers:{ deep:true,//开启深度监视。 handler(){ console.log("numbers改变了") } }, }, computed:{ info(){ return this.isHot? '炎热' : '凉爽' }, } }) // vm.$watch('info',{ // immediate:true, // handler(newValue,oldValue){ // console.log("info的值被修改了",newValue,oldValue) // } // }) </script> </body>
天气案例
<body> <div id="root"> <h3>今天天气是{{info}}</h3><!--用计算属性--> <button @click="changeWeather">切换天气</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ isHot:true }, methods:{ changeWeather(){ this.isHot = !this.isHot; } }, computed:{ info(){ return this.isHot? '炎热' : '凉爽' }, } }) </script> </body>
列表过滤
</head> <body> <!-- v-for指令 1.用于展示列表数据 2.语法:v-for="{item,index} in xxx" :key="yyy" 3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少) --> <div id="root"> <input type="text" v-model="keyWord" /> <h2>列表渲染(遍历)</h2> <ul> <li v-for="p in fieArr" :key="p.id"> {{p.name}}-{{p.age}} </li> </ul> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ keyWord:"", Arr:[ {id:001,name:"周冬雨",age:"18"}, {id:002,name:"马冬梅",age:"19"}, {id:003,name:"周杰伦",age:"20"}, {id:004,name:"温兆伦",age:"21"} ], fieArr:[], }, //用监视的方法来改变要筛选的值,然后在收取出来 watch:{ //要监视的对象,那么这里要监视keyWord,因为keyWord变化带动整个筛选 keyWord:{ immediate:true, handler(value){ this.fieArr = this.Arr.filter((p)=>{ return p.name.indexOf(value) !==-1; }) } } } }) </script> </body>
列表过滤computed
<body> <!-- v-for指令 1.用于展示列表数据 2.语法:v-for="{item,index} in xxx" :key="yyy" 3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少) --> <div id="root"> <input type="text" v-model="keyWord" /> <h2>列表渲染(遍历)</h2> <ul> <li v-for="p in fieArr" :key="p.id"> {{p.name}}-{{p.age}} </li> </ul> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ keyWord:"", Arr:[ {id:001,name:"周冬雨",age:"18"}, {id:002,name:"马冬梅",age:"19"}, {id:003,name:"周杰伦",age:"20"}, {id:004,name:"温兆伦",age:"21"} ], }, computed:{ fieArr(){ return this.Arr.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1 }) } } }) </script> </body>
列表排序
<body> <!-- v-for指令 1.用于展示列表数据 2.语法:v-for="{item,index} in xxx" :key="yyy" 3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少) --> <div id="root"> <input type="text" v-model="keyWord" /> <h2>列表渲染(遍历)</h2> <ul> <li v-for="p in fieArr" :key="p.id"> {{p.name}}-{{p.age}} </li> </ul> <button type="button" @click="sortType=0">原顺序</button> <button type="button" @click="sortType=1">降序</button> <button type="button" @click="sortType=2">升序</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ sortType:0, keyWord:"", Arr:[ {id:001,name:"周冬雨",age:"18"}, {id:002,name:"马冬梅",age:"19"}, {id:003,name:"周杰伦",age:"20"}, {id:004,name:"温兆伦",age:"21"} ], }, computed:{ fieArr(){ const type = this.Arr.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1 }) if(this.sortType){ type.sort((p1,p2)=>{ return this.sortType ==1 ?p2.age-p1.age : p1.age-p2.age }) } return type; } } }) </script> </body>
列表渲染
<body> <!-- v-for指令 1.用于展示列表数据 2.语法:v-for="{item,index} in xxx" :key="yyy" 3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少) --> <div id="root"> <!--遍历数组--> <h2>人员列表(遍历数组)</h2> <ul> <!-- <li v-for="p in Arr" :key="id"> {{p.name}}-{{p.age}} </li> --> <!--括号里面的第一个参数是遍历数组的值,第二个参数是索引值--> <!-- <li v-for="(p,index) in Arr" :key="id"> {{p.name}}-{{p.age}}-{{index}} </li> --> </ul> <!-- <h2>汽车列表(遍历对象)</h2> <ul> <li v-for="(p,index) in car" :key="index"> {{p}}-{{index}} </li> </ul> --> <!-- <h2>字符串列表(遍历字符串)</h2> <ul> <li v-for="(p,index) in str" :key="index"> {{p}}-{{index}} </li> </ul> --> <h2>数字列表(遍历数字)</h2> <ul> <li v-for="(p,index) in 5" :key="index"> {{p}}-{{index}} </li> </ul> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ Arr:[ {id:001,name:"黄健聪",age:"18"}, {id:002,name:"张晓靖",age:"18"}, {id:003,name:"张国荣",age:"18"} ], car:{ name:"宝马", price:"50万" }, str:"hello" } }) </script> </body>
key的作用和原理
<body> <!-- 1.index作为key可能会引发的问题: (1).若对数据进行:逆序添加,逆序删除等破坏顺序操作: 会产生没有必要的真实的DOM更新 ===> 界面效果没问题,但效率低 (2).如果结构中还包含输入类的DOM: 会产生错误DOM更新 ===>界面有问题 2.开发中然后选中key?: (1).最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值。 (2).如果不存在对象数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染例表用于展示,使用index作为key是没有问题的。 --> <div id="root"> <h2>人物列表(遍历人物)</h2> <ul> <li v-for="p in Persons" :key="p.id"> {{p.name}}-{{p.age}} <input type="text" /> </li> </ul> <button @click="add">点我添加老刘</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ Persons:[ {id:001,name:"黄健聪",age:"18"}, {id:002,name:"张晓靖",age:"18"}, {id:003,name:"张国荣",age:"18"} ], }, methods: { add(){ var p = {id:004,name:"老刘",age:"40"} this.Persons.unshift(p); } }, }) </script> </body>
生命周期
<body> <!-- 生命周期: 1.又名:生命周期回调函数、生命周期函数、生命周期钩子。 2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数 3.生命周期函数的名字不可更改,但哈桑农户䣌具体内容是程序员根据需求编写的 4.生命周期函数中的this指向的是vm 或者 组件实例对象 --> <div id="root"> <h2 :style="{opacity}">今天继续学习Vue</h2> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ opacity:1 }, //生命周期挂载 //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted mounted(){ setInterval(()=>{ this.opacity-=0.1; if(this.opacity <=0) this.opacity=1 },100) }, }) </script> </body>
收集表单数据
<body> <!-- 收集表单数据: 若:<input type="text" />,则v-model收集的是value值,用户输入的就是value值。 若:<input type="radio" />,则v-model收集的是value值,且要给标签配置value值。 若:<input type="checkbox" /> 1.没有配置value属性的input,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2.配置value属性的input (1).v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值) (2).v-model的初始值是数组,那么收集的就是value组成的数组 备注:v-model的三个修饰符: lazy:失去焦点再收集数据 number:输入字符串转为有效的数字 trim:输入首尾空格过滤 --> <div id="root"> <form @submit.prevent="demo"> <!--trim 去除字符串前后的空格--> 账号:<input type="text" v-model.trim="userInfo.name" /><br /><br /> 密码:<input type="password" v-model="userInfo.name" /><br /><br /> 年龄:<input type="number" v-model.number="userInfo.age" /><br /><br /> 性别:<!--单选一个的话,要用同一个name属性,这样子就可以实现单选的效果--> 男<input type="radio" name="sex" v-model="userInfo.sex" value="male" /> 女<input type="radio" name="sex" v-model="userInfo.sex" value="female" /><br /><br /> 爱好: 学习:<input type="checkbox" v-model="userInfo.hobby" value="study" /> 打游戏:<input type="checkbox" v-model="userInfo.hobby" value="game" /> 吃饭:<input type="checkbox" v-model="userInfo.hobby" value="food" /><br /><br /> 所属校区: <select v-model="userInfo.city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="guangdong">广东</option> </select> <br /><br /> 其他信息: <textarea v-model="userInfo.other"></textarea><br /><br /> <!--lazy 表示当该输入失去焦点的时候再收集输入的数据--> <input type="checkbox" v-model.lazy="userInfo.agree" />阅读并接受<a href="www.baidu.com">《注意条款》</a> <button>提交</button> </form> </div> <script src="text/javascript"> const vm = new Vue({ el:"#root", data:{ userInfo:{ name:"", age:"", sex:"", hobby:[], city:"", other:"", agree:"" } }, methods: { demo(){ alert("1") } }, }) </script> </body>
条件渲染
<body> <!-- 条件渲染 1.v-if 写法: (1).v-if = "表达式" (2).v-else-if = "表达式" (3).v-else = "表达式" 适用于:切换频率较低的场景 特点:不展示的DOM元素未被移除 注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被"打断"。 2.v-show 写法:v-show="表达式" 适用于:切换频率较高的场景。 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉 3.备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到 --> <div id="root"> <h2>当前的n值是{{n}}</h2> <button @click="n++">点我+1</button> <!--使用v-show做条件渲染--> <!--<h2 v-show="false">大家好,我的名字叫{{name}}</h2>--> <!--<h2 v-show="1 === 1">大家好,我的名字叫{{name}}</h2>--> <!--使用v-if做条件渲染--> <!--<h2 v-if="false">大家好,我的名字叫{{name}}</h2>--> <!--<h2 v-if="1 === 1">大家好,我的名字叫{{name}}</h2>--> <!--v-else和else-if--> <div v-if="n === 1">Angular</div> <div v-else-if="n === 2">React</div> <div v-else-if="n === 3">Vue</div> <!--template只能与v-if配合使用 这样子可以方便一下子显示相同的条件出来,也不破坏控制器里面的完整结构 --> <template v-if="n === 1"> <h3>你好</h3> <h3>黄健聪</h3> <h3>张晓靖</h3> </template> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ name:"黄健聪", n:0, } }) </script> </body>
自定义函数
自定义函数
<body> <!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍 需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 --> <div id="root"> <h3>当前的n值是</nbsp><span v-text="n"></span></h3> <h3>当前的n值是</nbsp><span v-big="n"></span></h3> <button @click="n++">点我+1</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ n:1 }, directives:{ big(element,bangding){ element.innerText = bangding.value*10 } } }) </script> </body>
自定义函数2
<body> <!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍 需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 --> <div id="root"> <h3>当前的n值是</nbsp><span v-text="n"></span></h3> <h3>当前的n值是</nbsp><span v-big="n"></span></h3> <h3>当前的n值是</nbsp><input v-fbind:value="n"></input></h3> <button @click="n++">点我+1</button> </div> <script type="text/javascript"> const vm = new Vue({ el:"#root", data:{ n:1 }, directives:{ big(element,bangding){ element.innerText = bangding.value*10 }, fbind:{ //指令与元素成功绑定时(一上来) bind(element,bangding){ element.value = bangding.value; }, //指令所在元素被插入页面时 inserted(element,bangding){ element.focus(); }, //指令所在的模板被重新解析时 update(element,bangding) { element.value = bangding.value; }, } } }) </script> </body>
自定义函数全局版
<body> <!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍 需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 --> <div id="root"> <h3>当前的n值是</nbsp><span v-text="n"></span></h3> <h3>当前的n值是</nbsp><span v-big="n"></span></h3> <h3>当前的n值是</nbsp><input v-fbind:value="n"></input></h3> <button @click="n++">点我+1</button> </div> <div id="root2"> <h3>当前的n值是</nbsp><input v-fbind:value="x"></input></h3> </div> <script type="text/javascript"> //全局写法 Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element,bangding){ element.value = bangding.value; }, //指令所在元素被插入页面时 inserted(element,bangding){ element.focus(); }, //指令所在的模板被重新解析时 update(element,bangding) { element.value = bangding.value; }, }) const vm = new Vue({ el:"#root", data:{ n:1 }, //自定义配置 directives:{ big(element,bangding){ element.innerText = bangding.value*10 }, fbind:{ //指令与元素成功绑定时(一上来) bind(element,bangding){ element.value = bangding.value; }, //指令所在元素被插入页面时 inserted(element,bangding){ element.focus(); }, //指令所在的模板被重新解析时 update(element,bangding) { element.value = bangding.value; }, } } }) const vm2 = new Vue({ el:"#root2", data:{ x:1, } }) </script> </body>
Vue_浏览器本地存储
<!-- Window.sessionStorage 和 Window.localStorage统称为WebStorage 1.浏览器端通过Window.sessionStorage(当浏览器关闭时,里面存储的数据也将跟着清空)和Window.localStorage(当浏览器关闭时,里面存储的数据不会清空,并随着浏览器再次打开时,还是存储在原位)属性来实现本地存储机制 2.相关API: 1.sessionStorage / localStorage.setItem('key','value'); 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值 2.sessionStorage / localStorage.getItem('key'); 该方法接受一个键名作为参数,返回键名对应的值 3.sessionStorage / localStorage.removeItem('key'); 该方法接受一个键名作为参数,并把该键名从存储中删除 4.sessionStorage / localStorage.clear(); 该方法会清空存储中的所有数据 备注: 1.sessionStorage存储的内容会随着浏览器窗口关闭而消失。 2.localStorage存储的内容,需要手动清除才会消失 3.sessionStorage / localStorage.getItem('key')如果里面的key对应的value获取不到,那么getItem的返回值时null 4.JSON.parse(null) 的结果依然是null --> <body> <button οnclick="saveLocal()">点我保存一个数据</button> <button οnclick="readLocal()">点我读取一个数据</button> <button οnclick="deleteLocal()">点我删除一个数据</button> <button οnclick="clearLocal()">点我清空数据</button> <script type="text/javascript"> //当浏览器要保存一个对象时 let p = {name:"黄健聪",age:18} function saveLocal(){//setItem是设置保存数据 localStorage.setItem('msg','hello') localStorage.setItem('Person',JSON.stringify(p))//当使用JSON.stringify()时,可把对象转为正常的显示 } function readLocal(){ //读取打印 console.log(localStorage.getItem('msg')); let result = localStorage.getItem('Person') console.log(JSON.parse(result)) } function deleteLocal(){ localStorage.removeItem('msg') } function clearLocal(){ localStorage.clear() } </script> </body>
下面使用的是Vue的组件化,后缀名为vue的
Vue_mixin混入配置
<!-- mixin(混入) 功能:可以把多个组件共用的配置提取成一个混入对象 使用方式: 第一步定义混合,例如 分别暴露export const mixin={ data(){...} methods:{...} ... } 第二步使用混入,例如: (1).全局混入:Vue.mixin(混入对象名(mixin)) (2).局部混入:mixins:['混入对象名(mixin)'] -->
Vue_plugins插件
//如果本组件里面声明了和混入配置一样的data属性,那么本组件data的属性优先级大于混合配置的
export default{ install(Vue){ //全局过滤器 Vue.filter('mySlice',function(value){ return value.slice(0,4) }) //全局自定义组件 Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element,bangding){ element.value = bangding.value; }, //指令所在元素被插入页面时 inserted(element,bangding){ element.focus(); }, //指令所在的模板被重新解析时 update(element,bangding) { element.value = bangding.value; }, }) //全局定义混入 Vue.mixin({ data(){ return{ a:100 } } }) } }
Vue_props配置
<!-- 配置项props 功能:让组件接收外部传过来的数据 (1).传递数据: <组件名 name="xxx" /> (2).接收数据: 第一种方式(只接收): props:['name' '....' ] 第二种方式(限制类型) props:{ name:String, age:Number } 第三种(限制类型、限制必要性、指定默认值); props:{ name:{ type:String,类型 required:true,必要性 default:'老王';默认值,一般与必要性不能一起用 } } 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会出现警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据 -->
<Student name="黄健聪" :age="18" sex="男" /><!--age上加上 : 等于获取引号里面的数字从而不是字符串类型-->
Vue_scoped属性
scoped样式 作用:让样式在局部生效,防止冲突 写法:<style scoped></style> 加上scoped时,那么就算其他组件有共同的class名,也会只服务当前区域的class
<!--当引入样式时: import Student from './components/Student.vue' import School from './components/School.vue'//当这里的组件有相同的class样式时,会先应用后面的,因为会覆盖掉前面的并且是后来居上的原理-->
Vuetoolist案例浏览器本地存储
1.当使用JSON.stringify()时,可把对象转为正常的显示 如代码所示: //当浏览器要保存一个对象时 let p = {name:"黄健聪",age:18} function saveLocal(){//setItem是设置保存数据 window.localStorage.setItem('Person',JSON.stringify(p)) //当使用JSON.stringify()时,可把对象转为正常的显示 } 得到:
2.当使用JSON.parse()时,可把对象转为正常的显示
如下图所示:
得到:
Vue自定义组件事件
##组件的自定义事件 1.一种组件间通信的方式,适用于:子组件===>父组件 2.使用场景:A是父组件,B是子组件,B想给A传递数据,那么就要在A中给B绑定自定义事件(事件的回调) 3.绑定自定义事件: 1.第一种方式,在父组件中:例:<Student @huangjiancong="demo" />或<Student v-on:huangjiancong="demo" /> 2.第二种方式,在父组件中: 例:<Student ref="student" /> 回调函数 demo(name,...params){ //当子元素传入多个元素给到父元素时,可以用...params来声明一个数组存放 console.log('app的demo被调用了',name,params) this.Studentname=name }, mounted(){ this.$refs.student.$once('huangjiancong',this.demo) } 3.若想让自定义事件只能触发一次,可以使用once--<Student v-on.once:huangjiancong="demo" /> 加上once之后,事件只能触发一次 或 mounted(){ this.$refs.student.$once('huangjiancong',this.demo) } 4.触发自定义事件:this.$emit('huangjiancong',想传过去的数据) 5.解绑自定义事件:this.$off('huangjiancong')--只能解绑一个 6.组件上也可以绑定原生DOM事件,需要使用native修饰符. 7.注意:通过this.$refs.ref绑定的数据.$on('huangjiancong',上面的回调函数)绑定自定义事件时,回调要么配置在methods(像上面的那个回调函数那样子写),要么用箭头函数,否则this的指向会出问题
全局事件总线
## 全局事件总线(GlobalEventBus)--->一种组件间通信的方式,适用于任意组件间通信
1.安装全局事件总线:
(1).在main.js上的
new Vue({ beforeCreate(){ Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm } })
2.使用事件总线:
(1).接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组组件自身
methods(){ demo(data){ ..... } } mounted(){ this.$bus.$on('xxx',this.demo) 如果没有用到方法的话,那就得用箭头函数来代替 } ```
(2).提供数据:this.$bus.$emit('xxx',数据)
3.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
消息的订阅(subscibe)与发布(publish)
## 1.一种组件间通信的方式,适用于任意组件通信。
2.使用步骤:
1.安装pubsub:npm i pubsub-js
2.引入:import pubsub from 'pubsub-js' 无论是接收的还是传递的都要引入
3.接收数据:A组件想接收数据,则在A组件中订阅消息(即接收数据的),订阅的回调留在A组件自身。
methods(){ demo(data){ ..... } }, mounted(){ this.pid = pubsub.subscribe('xxx',this.demo) 订阅消息 如果不用方法的话,那就直接箭头函数声明 }
4.提供消息:pubsub.publish('xxx',数据)
5.最好在beforeDestroy中,用pubsub.unsubscribe(this.pid)去取消订阅
$nextTick(function(){})(在增加编辑的Vue里面使用)
## nextTick
1.语法:this.$nextTick(function(){})
2.作用:在下一次DOM更新结束后执行其指定的回调
3.什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在this.$nextTick(function(){})所指定的回调函数中执行
过渡与动画
Vue封装的过渡与动画
1.作用:再插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
2.写法:
1.准备好样式:
1.元素进入的样式:
(1).v-enter:进入的起点
(2).v-enter-active:进入过程中
(3).v-enter-to:进入的终点
2.元素离开的样式:
(1).v-leave:离开的起点
(2).v-leave-active:离开的过程中
(3).v-leave-to:离开的终点
3.使用<transition>包裹要过度的元素,并配置name属性:
```Vue
<transition> <h1 v-show="isShow">你好啊!</h1> </transition> ```
4.备注:若有多个元素需要过渡,则需要使用:<transition-group> ,且给每个元素都要指定key值
```Vue <!-- 多个元素过渡 --> <transition-group appear> <h1 v-show="!isShow" key="1">你好啊</h1> <h1 v-show="isShow" key="2">大家好</h1> </transition-group>
配置代理方式1and方式2
## 方法二
编写vue.config.js配置具体代理规则:
//方法二 devServer: { proxy: { '/api': { //匹配所有以 '/api1'开头的请求路径 target: 'http://localhost:5000', //要访问的服务器(获取数据) pathRewrite:{'^/api':''}, ws: true,//用于支持websocket changeOrigin: true//用于控制请求头中的host值 }, '/demo': { target: 'http://localhost:5001', //要访问的服务器(获取数据) pathRewrite:{'^/demo':''}, ws: true,//用于支持websocket changeOrigin: true//用于控制请求头中的host值 } } }
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:(要拿数据服务器的端口)localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:(本机端口)localhost:8080
changeOrigin默认为true
*/
插槽
## 插槽
1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件
2.分类:默认插槽、具名插槽、作用域插槽
3.使用方式:
1.默认插槽:
父组件中:
<category> <div>html结构1</div> </catgory>
子组件中:
<template> <div class="category"> <!--定义插槽--> <slot>插槽默认内容....</slot> </div> </template>
2.具名插槽:
父组件:
<category title="游戏"> <ul slot="center"> <li v-for="(item,index) in games" :key="index"> {{item}} </li> </ul> <div slot="footer"> <a href="#">单机游戏</a> <a href="#">网络游戏</a> </div> </category>
子组件:
<template> <div class="category"> <h3>{{title}}</h3> <!--定义插槽--> <slot name="center"></slot> <slot name="footer"></slot> </div> </template>
3.作用域插槽:
1.理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者决定。(games数据在category组件中,但使用数据所遍历出来的结构由App组件决定)
<template> <div class="container"> <category title="Beyond"> <!--要想接收子组件传来的数据,一定要用到template 无序列表--> <template scope={games}> <ol> <li v-for="(item,index) in games" :key="index"> {{item}} </li> </ol> </template> </category> <!--有序列表--> <category title="游戏"> <template scope={games}> <ul> <li v-for="(item,index) in games" :key="index"> {{item}} </li> </ul> <a href="#">单机游戏</a> <a href="#">网络游戏</a> </template> </category> <!--生成h4标签--> <category title="视频"> <template scope={games}> <h3 v-for="(item,index) in games" :key="index"> {{item}} </h3> </template> </category> </div> </template>
子组件中:
<script> export default { name:"category", props:['title'], data() { return { music:['光辉岁月','不再犹豫','海阔天空','情人'], games:['Gta5','荒野大嫖客','QQ飞车','CF'], films:['哈利波特','精灵旅社','新灰姑娘','密室逃亡'] } }, } </script>
Vuex
## 搭建vuex环境
1.创建文件:src/store/index.js
//该文件用于创建Vuex中最为核心的store
//先下载插件 npm i vuex@3 ---备注下载vuex3 如果没有@3的话就默认下载vuex4,vue2下载vuex4会报错 (vue2搭配vuex3,vue3搭配vuex4)
//1.引入Vuex import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) //准备actions——用于响应组件中的动作 const actions = {}, //准备mutations——用于操作数据(state) const mutations = {}, //准备state——用于存储数据 const state = { } //创建并暴露(导出)store export default new Vuex.Store({ actions, mutations, state, })
2.在main.js中创建vm时传入store配置项
import Vue from 'vue' import App from './App.vue' import store from './store/index' Vue.config.productionTip = false new Vue({ el:"#app", store, render: h => h(App), })
2.基本使用
1.初始化数据、配置actions、配置mutations、操作文件store.js
//该文件用于创建Vuex中最为核心的store //先下载插件 npm i vuex@3 ---备注下载vuex3 如果没有@3的话就默认下载vuex4,vue2下载vuex4会报错 (vue2搭配vuex3,vue3搭配vuex4) //1.引入Vuex import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) //准备actions——用于响应组件中的动作 const actions = { addActions(context,value){ context.commit('addmutations',value) }, subActions(context,value){ context.commit('submutations',value) }, jiaddActions(context,value){ if(context.state.sum%2){ context.commit('addmutations',value) } }, addWaitActions(context,value){ setTimeout(()=>{ context.commit('addmutations',value) },2000) } } //准备mutations——用于操作数据(state) const mutations = { addmutations(state,value){ state.sum += value }, submutations(state,value){ state.sum -= value }, } //准备state——用于存储数据 const state = { sum:0 } //创建并暴露(导出)store export default new Vuex.Store({ actions, mutations, state, })
2.组件中读取vuex中的数据:$store.state.sum
3.组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)或$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,既不写dispatch,直接编写commit
getters的使用
4.getters的使用
1.概念:当state中的数据需要经过加工后再使用时,可以使用getters加工
2.在store.js中追加getters配置
...... const getters = { bigSum(state){ return state.sum*10 } } //创建并暴露(导出)store export default new Vuex.Store({ actions, mutations, state, getters })
3.组件中读取数据:$store.getters.bigSum(getters里面定义的函数)
四个map方法的使用
## 四个map方法的使用
1.mapState方法:用于帮助我们映射state中的数据为计算属性
computed:{ //借助mapState生成计算属性,从state中读取数据。(对象写法) key值可以跟value值名字不一样 //...mapState({sum:'sum',school:'school',subject:'subject'}) //借助mapState生成计算属性,从state中读取数据。(数组写法) key值可以跟value值名字要一样实则对应上面的sum:'sum' ...mapState(['sum','school','subject']), }
2.mapGetters方法:用于帮助我们映射getters中的数据为计算属性
computed:{ //借助mapGetters生成计算属性,从state中读取数据。(对象写法) key值可以跟value值名字不一样 //...mapGetters({bigSum:'bigSum'}) //借助mapGetters生成计算属性,从state中读取数据。(数组写法) key值可以跟value值名字要一样,实则对应上面的bigSum:'bigSum' ...mapGetters(['bigSum']) }
模块化+命名空间
1.目的:让代码更好维护,让多种数据分类更加明确。
2.修改store.js
const countAbout = { namespaced = true,//开启命名空间 state:{x:1}, mutations:{...} actions:{...} getters:{ bigSum(state){ return state.sum*10 } } } const personAbout = { namespaced = true,//开启命名空间 state:{x:1}, mutations:{...} actions:{...} getters:{ bigSum(state){ return state.sum*10 } } } const store = new Vuex.Store({ modules:{ countAbout, personAbout } })
3.开启命名空间后,组件中读取state数据:
//方式一,自己直接读取 this.$store.state.personAbout.list //方式二,借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
4.开启命名空间后,组件中读取getters数据:
...mapState('countAbout',['sum','school','subject']),
封装axios进行api的调用
1.先创建一个名为api的文件夹 axios,vuex
1.先进行下载关键的插件 npm i axios npm i vuex@3(vue2下载版本3的vuex,否则会出现版 本过高的报错).
2.在api的文件夹里面创建一个封装axios的文件(request.vue),文件内容如下:
//对于axios进行二次封装
import axios from 'axios';
//引入进度条 start:表示进度条的开始 ,done表示进度条的结束
import nprogress from 'nprogress';
//引入进度条的样式
import 'nprogress/nprogress.css'
//1.利用axios对象方法create,去创建一个axios实例
//2.requests就是axios,只不过稍微配置一下
const requests = axios.create({
//配置对象
//基础路径,发送请求的时候,路径当中会出现api
baseURL:'/api',
//代表请求超时的时间5s
timeout:5000
});
//请求拦截器:在发送请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
nprogress.start()
//config:配置对象,对象里面有一个属性很重要,headers请求头
return config
})
//响应拦截器
requests.interceptors.response.use((res)=>{
nprogress.done()
//成功的回调函数,服务器相应的数据回来之后,响应拦截器可以检测到,可以做一些事情
return res.data
},(error)=>{
//响应失败的回调函数
return Promise.reject(new Error('faile'))
})
//向外暴露
export default requests
3.继续在api的文件夹里面创建一个统一管理api的文件,代码如下:
//这个文件是来建立统一API管理
import requests from "./request";
import mockRequest from './mockRequest'
//三级联动的接口
// /api/product/getBaseCategoryList get请求 无参数
//发送请求:axios发请求返回结果Promise对象
export const reqCategoryList = ()=>{
return requests({
url:'product/getBaseCategoryList',
method:'GET'
})
}