目录
Vue框架基础
vue导入
<script src="js/vue.js"></script>
vue挂载点
<div id='app'></div> <script> new Vue (){ el:'#app', } </script> // el 为挂载点,采用css3选择器与页面标签进行绑定,决定该vue对象控制的页面范围 // 挂载点只检索也i按中第一个匹配到的结果,所以挂载点一般都采用id选择器 // html与body标签不可以作为挂载点
vue变量
类似于Django中的模板语法
<div id="app"> <p>{{ msg }}</p> <p>{{ info }}</p> <h3>{{ msg }}</h3> </div> <script> new Vue (){ el:'#app', data:{ msg:'此处不留爷', info:'自有留爷处' } } console.log(app.$el); console.log(app.$data); </script> // 实例成员中的data是为vue页面模板提供数据变量的 // 访问实例成员可以用 vue实例.$成员名
vue事件
实例1:给P1标签添加点击事件,记录点击次数
实例2:给P2标签添加鼠标悬停、移除鼠标、点击等事件
<div id="app"> <p class="p1" v-on:click="fn">这是一个段落,被点击了{{ count }}下</p> <p class="p2" @mouseover="over" @mouseout="out" @click="hit">点我:{{ action }}</p> </div> <script> let app = new Vue({ el:'#app', data:{ count:0, action:'别点我' }, methods:{ func(){ this.count++; console.log(this.count); }, over(){ this.action = '你被盯上了' }, out(){ this.action = '你安全了' }, hit(){ this.action = '你真的点我了,你完了' } } }); </script> // methods就是为vue实例提供事件函数的 // this代表当前该vue实例对象 // 绑定事件用 v-on:事件名="触发函数名",也可使用简写:@事件名="触发函数名"
vue文本指令
<!--v-text:将所有内容做文本渲染 --> <p v-text="msg + '拼接内容'"></p> <!--v-html:可以解析html语法标签的文本 --> <p v-html="'<b>' + msg + '</b>'"></p> <p v-html="`<b>${msg}</b>`"></p>
vue过滤器
<div id="app"> // 默认将msg作为参数传给ff过滤器 <p>{{ msg|ff }}</p> // 过滤器可以嵌套,(num|f1)|f2,在num基础上先用f1过滤器,再用f2过滤器 <p>{{ num|f1|f2 }}</p> // 过滤器括号内可以传参,过滤器方法接受所有传入的参数,按传入的位置进行接收 <p>{{ msg,num|f3(1,2) }}</p> </div> <script> new Vue({ el: '#app', data: { msg: '你不是真正的快乐', num: 1 }, // 过滤器使用vue实例成员filters来指定过滤器函数 filters:{ ff(x,y){ console.log(x); console.log(y); return `<b>${x}</b>`; }, f1(x){ return x + 10 }, f2(x){ return x*5 }, f3(x,y,p,q){ console.log(x); console.log(y); console.log(p); console.log(q); }, }, })
vue事件指令
<p @click="f1">被点击了{{ count }}下</p> // 当事件函数没有传参数,默认传入事件对象 <div class="box" @click="f2(10, $event)"></div> // 事件函数一旦添加传参(),系统就不再传递任何参数,需要事件对象时,可以手动传入 $event methods: { f1(ev, b) { this.count ++; console.log(ev); // MouseEvent console.log(b); // undefined }, f2(num, ev) { console.log(num); // 10 console.log(ev); // MouseEvent } },
vue属性指令
<!--1.下方的class、id、title、abc等是div标签的属性,属性指令就是控制它们的--> <div class="b1" id="b1" v-bind:title="title" :abc="xyz"></div> <!--2.属性指令:v-bind:属性名="变量",简写方式 :属性名="变量" --> <!--只要是属性指令,属性值就为一个变量,需要在data成员中初始化 --> <!--class可以写两份,一份写死,一份有vue控制--> <div class="box1" :class="c2"></div> <!--{}控制类名,key为类名,key对应的值为bool类型,决定该类名是否起作用--> <div :class="{box2:true, circle:cable}"></div> <!--[]控制多个类名--> <div :class="[c3, c4]"></div>
作业
有 红、黄、蓝 三个按钮,以及一个200x200矩形框box,点击不同的按钮,box的颜色会被切换为指定的颜色
<style> .box { width: 200px; height: 200px; background-color: red; } </style> <body> <div id="app"> <p> <button @click="fn('red')">红</button> <button @click="fn('yellow')">黄</button> <button @click="fn('blue')">蓝</button> </p> <!-- :属性指令 --> <div class="box" :style="{backgroundColor: color}"></div> </div> </body>
<script> new Vue({ el: '#app', data: { color: 'red' }, methods: { fn(color) { this.color = color; } } }) </script>
有一个200x200矩形框wrap,点击wrap本身,记录点击次数,如果是1次wrap为pink色,2次wrap为green色,3次wrap为cyan色,4次重新回到pink色,依次类推
<style> .wrap { width:200px; height:200px; background-color:red; } </style> <div id="app"> <div class="wrap" :style="{backgroundColor: color}" @click="changeColor"> </div> </div>
new Vue({ el:'#app', data:{ color:'black', count:0, colorArr:['cyan', 'pink', 'green'] // 保存颜色的映射关系 }, methods:{ changeColor(){ let n = this.count++; this.color = this.colorArr[n % this.colorArr.length]; } } })
图形初始左红右绿,点击一下后变成上红下绿,再点击变成右红左绿,再点击变成下红上绿,依次类推
<style> .box { width: 200px; height: 200px; border: 1px solid black; border-radius: 50%; overflow: hidden; position: relative; } .b1 { background-color: red; position: absolute; } .b2 { background-color: green; position: absolute; } .l { width: 100px; height: 200px; left: 0; } .r { width: 100px; height: 200px; right: 0; } .t { width: 200px; height: 100px; top: 0; } .b { width: 200px; height: 100px; bottom: 0; } </style> <div id="app"> <div class="box" @click="clickAction"> <div class="b1" :class="c1"></div> <div class="b2" :class="c2"></div> </div> </div>
<script> let app = new Vue({ el: '#app', data: { count: 1, c1: 'l', c2: 'r', c1Arr: ['l', 't', 'r', 'b'], c2Arr: ['r', 'b', 'l', 't'] }, methods: { clickAction() { let n = this.count ++; this.c1 = this.c1Arr[n % 4]; this.c2 = this.c2Arr[n % 4]; } } }); // 利用定时器自动旋转图像 setInterval(function () { app.clickAction(); }, 500) </script>
vue表单指令
<div id="app"> <!--普通表单元素:用v-model直接绑定变量控制value的值 --> <input type="text" v-model="v1"> <input type="text" v-model="v1"> <span>{{ v1 }}</span> <br> <!--单一复选框:v2的值为true时选中,为false时不选中--> <input type="checkbox" v-model="v2"> <br> <!--多个复选框:给定v3为初始选中的列表,列表内放选中的value属性值。--> 唱: <input type="checkbox" name="hobby" value="sing" v-model="v3"> 跳: <input type="checkbox" name="hobby" value="dance" v-model="v3"> rap: <input type="checkbox" name="hobby" value="rap" v-model="v3"> <br> <!--单选框:给定v4为指定默认选中的单选框value的属性值--> 男:<input type="radio" value="male" v-model="v4"> 女:<input type="radio" value="famale" v-model="v4"> </div> <script> new Vue({ el: '#app', data:{ v1:123, v2:false, v3:['sing','rap'], v4:'male' } }) </script>
vue条件指令
<div id="app"> <!-- v-if: 值为false时,在页面上不渲染,并且隐藏标签中的信息--> <p v-if="false">if</p> <!-- v-show: 值为false时,在页面上是用display:none 渲染隐藏的,但是仍然存在当前页面的结构中 --> <p v-show="false">show</p> <!--上分支成立时,所有的下分支都会被屏蔽,v-else只有在上分支全部为假时才会显示,所以v-else不需要条件--> <p v-if="1">if</p> <p v-else-if="0">elif</p> <p v-else-if="0">elif</p> <p v-else>else</p> </div>
vue条件指令实例
<style> .box { width: 200px; height: 200px; } .r {background-color: red} .g {background-color: green} .b {background-color: black} .action{background-color: pink} </style> <div id="app"> <!-- 给定button的单击事件并传入参数,并且给button绑定{}属性指令:判断当前c变量的值来确定选中按钮的高亮--> <button @click="change('red')" :class="{ action:c === 'red' }">红</button> <button @click="change('green')" :class="{ action:c === 'green' }">绿</button> <button @click="change('black')" :class="{ action:c === 'black' }">黑</button> <br> <!-- 利用v-if家族来判断变量c的值来确定是否显示该标签 --> <div class="box r" v-if="c === 'red'"></div> <div class="box g" v-else-if="c === 'green'"></div> <div class="box b" v-else></div> </div> <script> new Vue({ el: '#app', data:{ // localStorage是浏览器永久的数据库,可以将c变量存储在其中记录最后一次点击状态。 // 判断localStorage中是否有变量c,有的话则使用里面的c,没有就用默认值red c: localStorage.c ? localStorage.c : 'red', }, methods:{ change(color){ this.c = color; // 将最后一次的点击状态保存在localStorage中,方便下一次打开时找到变量c的值 localStorage.c = color; } } }) </script>
vue循环指令
<div id="app"> <!--循环指令:v-for="成员 in 容器"--> <!--循环数组:数组里可以是任意数据类型的数据--> <p v-for="v in lis">{{ v }}</p> <!--循环的成员可以为两个参数,第一个为value值,第二个为index索引--> <p v-for="(v,i) in lis">{{ i }}:{{ v }}</p> <!--实例:在每两个循环成员之间加一个|,不包括首尾--> <p> <span v-for="(v,i) in lis"> <span v-if="i != 0"> | </span> {{ v }} </span> </p> <!--循环对象时:只接收一个参数只循环对象的值--> <p v-for="u in user"> {{ u }} </p> <!--循环对象时:接收两个参数循环对象的值和键--> <p v-for="(u,k) in user"> {{ k }}:{{ u }} </p> <!--循环对象时:接收三个参数循环对象的值、键和索引--> <p v-for="(u,k,i) in user"> {{ i }}--{{ k }}:{{ u }} </p> <!--循环遍历列表套对象,显示出每个对象的键与值,并且在每两个对象之间添加分割线--> <div v-for="(stu,i) in students"> <hr v-if="i != 0"> <p v-for="(v,k) in stu"> {{ k }}:{{ v }} </p> </div> </div> <script> new Vue({ el: '#app', data:{ lis:['西游记','水浒传','红楼梦','三国演义',[1,2,3],{'name':'wang'}], user:{'name':'wang','age':18,'gender':'male'}, students: [ { name: "Bob", age: 18 }, { name: "Tom", age: 17 }, { name: "Jerry", age: 19 } ] }, }) </script>
vue循环指令实例
实现input框输入内容点击按钮同步到下方的评论内容中,并添加删除按钮删除评论。
<div id="main"> <input type="text" v-model="msg"> <button @click="send">留言</button> <ul> <li v-for="(v,i) in comments" > <button @click="deletes(i)">删除</button>{{ v }} </li> </ul> </div> <script> new Vue({ el:'#main', data:{ msg:'', comments:[] }, methods:{ send(){ if (this.msg) { this.comments.push(this.msg); this.msg = ''; } }, deletes(i){ // splice() 三个参数:开始索引、操作长度、操作的结果的集合 // 比如最后一个参数不行就是删除,全为0就是删除首个 this.comments.splice(i,1); } } }) </script>
vue分隔符成员
用来修改插值表达式的符号
new Vue({ el: '#app', data: { num: 100 }, delimiters: ['{[', ']}'], })
vue计算属性成员
<!--实现两个input框中的数据的和实时更新--> <div id="app"> <input type="text" v-model="v1"> + <input type="text" v-model="v2"> = <label>{{ res }}</label> </div> <script> new Vue({ el: '#app', data:{ v1:'', v2:'', }, // computed中定义的是方法属性,data中定义的也是属性,所以不需要重复定义属性,可以省略data里的 // 方法属性的值来源于绑定的方法的返回值,类似于python中的property装饰器,将方法封装成数据属性 // 方法属性必须在页面中渲染后,绑定的方法才会被调用 // 方法中出现的所有变量都会被监听,任何变量发生值更新都会调用一次绑定方法,重新更新方法属性的值 // 方法属性值不能手动设置,必须通过绑定的方法进行设置 // js属于弱类型语言,将字符串转换为整型可以在字符串前加'+'即可,前提是该字符串可以转换为整型 computed:{ res(){ if (this.v1 && this.v2){ return +this.v1 + +this.v2 }else{ return '结果' } // return this.v1 && this.v2 ? +this.v1 + +this.v2 : '结果'; } } }) </script>
vue属性的监听
<div id="app"> <p> 姓名:<input type="text" v-model="full_name"> </p> 姓:<span>{{ first_name }}</span> 名:<span>{{ last_name }}</span> </div> <script> new Vue({ el: '#app', data:{ full_name:'', first_name:'', last_name:'', }, watch:{ // watch中给已有的属性设置监听方法 // 监听的属性值一旦发生改变,就会调用该监听方法,进行逻辑处理 // 监听方法不需要返回值,return只有主动结束该方法的作用 full_name(){ if (this.full_name.length == 2){ this.first_name = this.full_name.split('')[0]; this.last_name = this.full_name.split('')[1]; } } } }) </script>
vue组件
组件:由html/css/js三部分组成的独立单位,可以类似于变量,重复使用
组件其实就是vue实例(对象),一个组件就是一个vue实例
new Vue() 产生的也是实例(对象),所以也是组件,我们称之为 根组件
一个页面建议只出现一个根组件
组件的html页面结构由template实例成员提供
template提供的html结构是用来构建虚拟DOM的
真实的DOM最终会被虚拟DOM替换
根组件一般不提供template,就由挂载点el来提供构建虚拟DOM的页面结构
根组件如果提供了template,还需要设置挂载点作为替换占位
template模板有且只有一个根标签
let c1 = ''; new Vue({ el: '#app', data: { msg: '12345', c1: 'red' }, template: ` <div id="app"> <p :style="{color: c1}">{{ msg }}</p> <p @click="clickAction">{{ msg }}</p> </div> `, methods: { clickAction() { console.log(this.msg) } } })
子组件:
// 定义组件:组件就是一个普通对象,内部采用vue语法结构,被vue注册解释后,就会成为vue组件 let tag = { template: ` <p>我是自定义的子组件</p> ` }; // 注册组件:子组件必须在Vue实例成员components里注册了之后才可以使用。 new Vue({ el:'#app', components:{ // 简写 tag, tag:tag, } }) // 全局组件:不需要注册就可以直接使用 Vue.component('mytag',{ template: `<h1>我是全局组件</h1>`, }); // 使用组件 <div id="app"> <tag></tag> <mytag></mytag> </div>
子组件的实际应用
在子组件中渲染好一小块页面,并且在重复使用组件中可以实现记录点击次数功能。
css <style> .wrap { width: calc(200px * 4 + 80px); margin: 0 auto; user-select: none; } .box { width: 200px; height: 260px; /*border: 1px solid black;*/ background-color: rgba(10, 200, 30, 0.5); border-radius: 10px; float: left; margin: 10px; } .box img { width: 100%; /*height: 200px;*/ border-radius: 50%; } .box p { text-align: center; } </style> <div id="app"> <div class="wrap"> <tag></tag> <tag></tag> <tag></tag> <tag></tag> </div> </div> <script> let titleTag = { template: ` <p> <b> 这是一种纯二哈 </b> </p> `, }; let tag = { template: ` <div class="box"> <img src="img/001.jpg" alt=""> <title-tag /> <p @click="fn"> 锤它:<b>{{ num }}下</b> </p> </div> `, // 能被复用的组件(除了根组件),数据都要做局部化处理, // 因为复用组件后,组件的数据是相互独立的 // data的值为绑定的方法的返回值,返回值是存放数据的字典 data () { return { num: 0 } }, methods: { fn() { this.num ++ } }, components: { // 注册用到的titleTag子组件 titleTag, } }; new Vue({ el: '#app', components: { // 注册tag子组件 tag, } }); </script>
vue组件传参-父传子
基于上面的子组件实例,自定义一个数组,数组里存放多个对象,由对象的title和图片地址,自定义组件,将数组中的对象渲染到页面中,有几个对象就渲染几个。
<div id="app"> <div class="wrap"> 绑定dog属性指令,将循环的dog对象传到子组件中,子组件就能拿到当前的dog对象了 <tag v-for="dog in dogs" :dog="dog"></tag> </div> </div> <script> let dogs = [ {title: '二哈1号', img: 'img/1.jpg',}, {title: '二哈2号', img: 'img/2.jpg',}, {title: '二哈3号', img: 'img/3.jpg',}, {title: '二哈4号', img: 'img/4.jpg',}, {title: '二哈1号', img: 'img/1.jpg',}, {title: '二哈2号', img: 'img/2.jpg',}, {title: '二哈3号', img: 'img/3.jpg',}, {title: '二哈4号', img: 'img/4.jpg',}, ]; let tag = { // 在子组件中,可以通过设置的自定义属性指令dog拿到外部给其传的值,props里面放一个数组,可以接收多个值。 props:['dog'], template: ` <div class="box"> <img :src="dog.img"> <p> <b>{{ dog.title }}</b> </p> <p @click="fn"> 攻击:<b>{{ num }}</b> </p> </div> `, data() { return { num: 0 } }, methods: { fn() { this.num++ } }, }; new Vue({ el: '#app', data:{ // 声明dogs数组变量 dogs, }, components: { // 注册tag子组件 tag, } }); </script>
localStorage存数组
localStorage直接将数组存储进去读出来的是字符串,逗号分隔符就会影响取值,所以,是不能直接存储数组和对象的,需要利用JSON序列化为json数据才能存储,取数据也需要先反序列化才能转化为数组或对象。
<script> localStorage.arr = JSON.stringify([1, 2, 3]); let res = JSON.parse(localStorage.arr); console.log(res, res[2]); </script>
vue组件传参-子传父
<style> ul { list-style: none; } .d-btn { font-size: 12px; width: 15px; display: inline-block; } .d-btn:hover { color: red; cursor: pointer; } </style> <div id="app"> <input type="text" v-model="msg"> <button @click="send_comment">留言</button> <ul> <tag v-for="(v, i) in comments" :msg="v" :index="i" @f1="deleteMsg"/> </ul> </div> <script> let tag = { props: ['msg', 'index'], template: ` <li> <i class="d-btn" @click="fn">x</i> <b>{{ msg }}</b> </li> `, methods: { fn () { // 点击子级,要告诉父级删除第几条数据,因为comments在父级中 // 需要通知父级 this.$emit('f1', this.index); } } }; new Vue({ el: '#app', data: { msg: '', comments: localStorage.comments ? JSON.parse(localStorage.comments) : [], }, components: { tag, }, methods: { send_comment() { if (this.msg) { this.comments.push(this.msg); this.msg = ''; localStorage.comments = JSON.stringify(this.comments); } }, deleteMsg(index) { this.comments.splice(index, 1); localStorage.comments = JSON.stringify(this.comments); } } }) </script>