地址 Vue的简介和使用
Vue全套教程全开源
4个小时带你快速入门vue
MVVM
M : 模型 , 对应数据
V : 视图 , 对应html
VM : 视图模型 , 对应Vue
Hello world 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <div id ="box" > {{ 10+20 }} <p > {{ myname }} {{ mysum }} {{ 20>10?'aaa':'bbb' }} </p > <p > {{ myhtml }} </p > <p v-html ="myhtml" > </p > </div > <script > var vm = new Vue({ el :"#box" , data :{ myname :"hyl" , mysum :10 +20 , myhtml :"<h1>heyingliang<h1>" , } }) </script >
data的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id ="box" > <p > {{ name }}</p > <p > {{ msg.age }} </p > <p > {{ li[0] }}</p > </div > <script > var vm = new Vue({ el :'#box' , data :{ name :'hyl' , msg :{ 'age' :21 ,'sex' :`nan` , }, li :[21 ,23 ,45 ] } }) </script >
指令 其实可以把指令看成是标签的属性
v-text 设置标签的文本值(textContent
)
1 2 3 4 5 6 7 8 9 10 11 12 <div id ="box" > <p v-text ="name" > </p > </div > <script > var vm = new Vue({ el :'#box' , data :{ name :'hyl' , } }) </script >
支持字符串的拼接
1 2 3 4 <div id ="box" > <p v-text ="name +` is sb`" > </p > <p > {{ name + ' is sb' }}</p > </div >
v-html 设置标签的innerHTML
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html
指令
1 2 3 4 5 6 7 8 9 10 11 12 <div id ="box" > <p v-html ="myhtml" > </p > </div > <script > var vm = new Vue({ el :"#box" , data :{ myhtml :"<h1>heyingliang<h1>" , } }) </script >
v-html
比v-text
更高级 :
v-html
内容中有html结构会被解析为标签
v-text
指令无论内容是什么只会解析为文本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div id ="box" > <p v-html ="name" > </p > <p v-html ="name2" > </p > </div > <script > var vm = new Vue({ el :'#box' , data :{ name :'hyl' , name2 :'<strong>123</strong>' , } }) </script >
v-on 为元素事件绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id ="box" > <button type ="button" value ="this is a button" v-on:click ="myfun" > </button > <button type ="button" value ="this is a button" @click ="myfun" > </button > </div > <script > var vm = new Vue({ el :'#box' , methods :{ myfun :function ( ) { alert("hello" ) } } }) </script >
点击h2 : hyl改变成dsz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div id ="box" > <h2 @click ="myfun" > {{ name }}</h2 > </div > <script > var vm = new Vue({ el :'#box' , data :{ name :'hyl' , }, methods :{ myfun :function ( ) { this .name = 'dsz' } } }) </script >
在Vue中 , 不要考虑如何改变元素 , 而是元素绑定数据 , 然后直接修改数据
事件修饰符 事件后面跟上.修饰符
可以对事件进行限制
比如.enter
可以限制触发的按键为回车
.stop
: 停止事件冒泡
.prevent
: 停止默认行为
.capture
.self
: 只有自己的行为才触发函数(事件冒泡上来的事件不会执行)
.once
: 只执行一次
.passive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <a v-on:click.stop ="doThis" > </a > <form v-on:submit.prevent ="onSubmit" > </form > <a v-on:click.stop.prevent ="doThat" > </a > <form v-on:submit.prevent > </form > <div v-on:click.capture ="doThis" > ...</div > <div v-on:click.self ="doThat" > ...</div > <input type ="input" v-on:keyup.13 ="doThat" > <input type ="input" v-on:keyup.enter ="doThat" >
事件冒泡现象依旧存在
事件冒泡 :
当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window 。
注意这里传递的仅仅是事件 并不传递所绑定的事件函数。
所以如果父级没有绑定事件函数,就算传递了事件 也不会有什么表现 但事件确实传递了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div id ="box" > <ul @click ="click_ul" > <li @click ="click_li" > a</li > <li @click ="click_li" > b</li > </ul > </div > <script > var vm = new Vue({ el : "#box" , methods : { click_li :function ( ) { console .log('click li' ) }, click_ul :function ( ) { console .log('click ul' ) } } }) </script >
点击了li , 会打印出click li
和click ul
Vue的函数会自动传入event事件本身
1 2 3 4 click_li:function (event ) { console .log('click li' ) event.stopPropagation(); },
这时我们就可以使用Vue的语法糖.stop
1 <a v-on:click.stop ="doThis" > </a >
同理:event.preventDefault()
: 阻止元素发生默认的行为(例如,当点击提交按钮时阻止对表单的提交 , a标签被点击时的页面跳转)
1 <a href ='http://www.baidu.com' @click.prevent ='myfunc' > aaa</a >
v-show 动态显示和隐藏
1 2 3 4 5 6 7 8 9 10 11 12 13 <div id ="box" > <p v-show ="isshow" > ppppp</p > </div > <script > var vm = new Vue({ el :"#box" , data :{ isshow :true , myhtml :"<h1>heyingliang<h1>" , } }) </script >
age大于18才显示
1 2 3 4 5 6 7 8 9 10 11 12 <div id ="box" > <p v-show ="age>=18" > isshow</p > </div > <script > var vm = new Vue({ el :"#box" , data :{ age :19 , } }) </script >
控制显示与隐藏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id ="box" > <button class ="btn btn-danger" @click ="func" > show or hide</button > <p v-show ="isshow" > isshow</p > </div > <script > var vm = new Vue({ el : "#box" , data : { isshow : false , }, methods : { func : function ( ) { this .isshow = !this .isshow } } }) </script >
v-if 动态创建和删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id ="box" > <p v-show ="isshow" > isshow</p > <p v-if ="iscreated" > iscreated</p > </div > <script > var vm = new Vue({ el :"#box" , data :{ isshow :true , iscreated :true , myhtml :"<h1>heyingliang<h1>" , } }) </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id ="box" > <button class ="btn btn-danger" @click ="myfunc" > show or hide</button > <h1 v-if ='show' > if-true</h1 > <h1 v-else > if-false</h1 > </div > <script > var vm = new Vue({ el : "#box" , data : { show : true , }, methods : { myfunc ( ) { this .show = !this .show } } }) </script >
还有v-else-if
关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div id ="box" > <h1 v-if ='num>0' > v-if --- num > 0</h1 > <h1 v-else-if ='num==0' > v-else-if --- num = 0</h1 > <h1 v-else > v-else --- num < 0</h1 > </div > <script > var vm = new Vue({ el : "#box" , data : { num : -1 , }, }) </script >
v-bind 用于绑定数据和元素属性 , 以此来修改元素属性 (比如 : src , title , class)
通常我们可以将v-bind:
简写成:
三目写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div class ="content" > <div id ="box" > <span v-bind:class ="isActive?'h1':'h6'" > 123</span > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { isActive : true , }, }) </script >
注意 , "isActive?'h1':'h6'"
, 三元表达式中要用两次引号
:class="{h1:isActive}"
, class是不是h1取决于isActive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div class ="content" > <div id ="box" > <span :class ="{h1:isActive}" > 123222222222222222</span > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { isActive : false , }, }) </script >
对象写法 v-bind
的绑定的对象是obj
, 那么就会有这个obj对象的所有属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div class ="content" > <div id ="box" > <span :class ="myobj" > 123222222222222222</span > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { myobj :{ active :true , h1 :true , flow :false , } }, }) </script >
这样 , span对象就会有active
和h1
两个class(flow因为为false,所以没有)
如果我们在console里查看vm.myobj
对象, 发现myobj对象有六个方法 ,
get active: ƒ reactiveGetter()
set active: ƒ reactiveSetter(newVal)
get h1: ƒ reactiveGetter()
set h1: ƒ reactiveSetter(newVal)
get flow: ƒ reactiveGetter()
set flow: ƒ reactiveSetter(newVal)
说明myobj对象的属性的设置和获取就是由这六个方法拦截重载的
所以 , 如果我们新增一个actIve2属性也没有用 , 因为没有重载方法
数组写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div class ="content" > <div id ="box" > <span :class ="myarr" > 123222222222222222</span > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { myarr :['h1' ,'active' ] }, }) </script >
之后只要使用vm.myarr.push('flow')
即可
三目的动态写法 1 2 3 <div :style ="'background" '+(isActive ?'red ': 'yellow ')"> 动态绑定style-三目写法.如果isActive为True,绑定red,否则绑定yellow </div >
对象的动态写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div class ="content" > <div id ="box" > <span :class ="cls" > 123222222222222222</span > <button class ="btn btn-default" @click ="toggle" > change</button > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { cls : 'h1' , }, methods :{ toggle :function ( ) { this .cls = 'h6' ; } } }) </script >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id ="box" > <button class ="btn btn-default" @click ="toggle" > change</button > <span class ="btn" :class ="{'btn-default':btn_style}" > 123</span > </div > <script > var vm = new Vue({ el : "#box" , data : { cls : 'btn-default' , btn_style :false , }, methods : { toggle : function ( ) { this .btn_style = true ; } } }) </script >
对象的动态写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <div class ="content" > <div id ="box" > <span :class ="myobj" > 123222222222222222</span > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { myarr :['h1' ,'active' ] }, }) </script >
1 vm.myarr.push({fontSize:'30px'})
v-for 列表循环
1 2 3 4 5 6 7 8 9 10 11 12 <div id ="box" > <h2 v-for ='(num,idx) in myarr' > {{num}}---{{idx}}</h2 > </div > <script > var vm = new Vue({ el : "#box" , data : { myarr :[11 ,22 ,33 ] }, }) </script >
还可以遍历对象的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <h2 v-for ='(value,key) in myobj' > {{value}}---{{key}}</h2 > </div > <script > var vm = new Vue({ el : "#box" , data : { myobj :{ 'name' :'hyl' , 'age' :'22' , 'sex' :'male' , } }, }) </script >
key的作用:
key是为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素 ,
需要为每项提供一个唯一的key属性。
列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;
也就是说 :
没有key属性时,状态默认绑定的是位置;
有key属性时,状态根据key的属性值绑定到了相应的数组元素。
数据更新 原地修改方法:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
非原地修改方法:
filter()
concat()
slice()
map()
注 : vue不能使用索引修改
同理 , 添加obj对象的属性 , 也可以使用set方法 . 他会自动定义obj的get重载方法和set重载方法
v-model 表单数据的双向绑定
vue中经常使用到<input>
和<textarea>
这类表单元素,vue对于这些元素的数据绑定和我们以前经常用的jQuery有些区别。vue使用v-model实现这些标签数据的双向绑定,它会根据控件类型自动选取正确的方法来更新元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id ="box" > <input type ="text" v-model ="message" @keyup.enter =myfunc /> {{message}} </div > <script > var vm = new Vue({ el : "#box" , data : { message :"132" , }, methods :{ myfunc ( ) { alert(this .message); } } }) </script >
v-model.lazy 区别 : 就是@input(时刻监听)
和 @change(监听焦点)
的区别 . v-model
是 时刻监听 , v-model.lazy
只会监听失去焦点的事件,节省资源
1 <input type ='text' v-model.lazy ='mytext' />
v-model.trim 去除空格
1 <inputtype='text' v-model.trim="username">
计算属性 1 2 3 4 5 6 7 8 9 10 11 12 <div id ="box" > <li > {{ mytext.substring(0,1).toUpperCase() + mytext.substring(1) }}</li > </div > <script > var vm = new Vue({ el : "#box" , data : { mytext :'heyingliang' , } }) </script >
上面做法其实是不妥当的 , 把js的处理逻辑放到模板里 , 很混乱 , 这时就可以使用计算属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div id ="box" > <li > {{ UpperText }}</li > </div > <script > var vm = new Vue({ el : "#box" , data : { mytext : 'heyingliang' , }, computed : { UpperText ( ) { return this .mytext.substring(0 , 1 ).toUpperCase() + this .mytext.substring(1 ) } } }) </script >
写成方法
, 但是最后是用属性
来获取
计算属性和计算方法的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id ="box" > <li > {{ UpperText }}</li > <li > {{ getUpperText() }}</li > </div > <script > var vm = new Vue({ el : "#box" , data : { mytext : 'heyingliang' , }, methods : { getUpperText : function ( ) { return this .mytext.substring(0 , 1 ).toUpperCase() + this .mytext.substring(1 ) } }, computed : { UpperText ( ) { return this .mytext.substring(0 , 1 ).toUpperCase() + this .mytext.substring(1 ) } } }) </script >
计算属性 : 会将计算的结果作为属性存储下来 , 下次直接使用即可 . 当且仅当依赖的改变了,才会重新执行一次
计算方法 : 每次都要重新计算
练习 分页计数器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <div class ="content" > <div id ="box" > <button class ="btn btn-danger" value ="-" @click ="dec()" > -</button > <span > {{ num }}</span > <button class ="btn btn-danger" value ="+" @click ="inc()" > +</button > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { num : 1 , }, methods : { inc : function ( ) { if (this .num == 10 ) { alert('到顶了' ); } else { this .num += 1 ; } }, dec : function ( ) { if (this .num == 1 ) { alert('到底了' ); } else { this .num -= 1 } } } }) </script >
模糊查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div id ="box" > <input v-model ="mytext" type ="text" @input ="myfunc" /> <h4 v-for ='value in myarr' > {{value}}</h4 > </div > <script > var vm = new Vue({ el : "#box" , data : { mytext : '' , myarr : ['aa' , 'bb' , 'cc' , 'dd' ], myarr2 :['aa' , 'bb' , 'cc' , 'dd' ], }, methods : { myfunc : function ( ) { this .myarr = this .myarr2.filter(item => item.indexOf(this .mytext)>-1 ); } } }) </script >
或者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id ="box" > <input v-model ="mytext" type ="text" /> <h4 v-for ='value in getdata' > {{value}}</h4 > </div > <script > var vm = new Vue({ el : "#box" , data : { mytext : '' , myarr : ['aa' , 'bb' , 'cc' , 'dd' ], }, computed :{ getdata ( ) { return this .myarr.filter(item => item.indexOf(this .mytext)>-1 ); } } }) </script >
非自动的轮播图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <div class ="content" > <div id ="box" > <img class ="img-responsive center-block" :src ="img_arr[img_idx]" /> <button class ="btn btn-default" v-show ="img_idx!=0" @click ="before" > before</button > <button class ="btn btn-default" v-show ="img_idx<img_arr.length-1" @click ="next" > next</button > </div > </div > <script > var vm = new Vue({ el : '#box' , data : { img_arr : ['static/1.png' , 'static/2.png' , 'static/3.png' , 'static/4.png' , 'static/5.png' ], img_idx : 0 , }, methods : { next : function ( ) { this .img_idx++; }, before : function ( ) { this .img_idx--; } } }) </script >
checkbox常用 多选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <label > Favorite sports</label > <input type ="checkbox" v-model ="check_list" value ='swimming' /> 游泳 <input type ="checkbox" v-model ="check_list" value ='run' /> 长跑 <input type ="checkbox" v-model ="check_list" value ='pingong' /> 乒乓 {{ check_list }} </div > <script > var vm = new Vue({ el : "#box" , data : { check_list : [] }, }) </script >
单选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <label > Favorite lang</label > <input type ="radio" v-model ="check" value ='python' /> python <input type ="radio" v-model ="check" value ='js' /> js <input type ="radio" v-model ="check" value ='java' /> java {{ check }} </div > <script > var vm = new Vue({ el : "#box" , data : { check :'' , }, }) </script >
简易购物车 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <div id ="box" > 全选:<input type ="checkbox" v-model ="isAllCheck" @change ="check_all" > <li v-for ="data in datalist" > <input type ="checkbox" v-model ="check_list" :value ='data' @change ="check_all2" > {{ data }} </li > {{check_list}} <h4 > money total:</h4 > {{ getSum() }} </div > <script > var vm = new Vue({ el : "#box" , data : { isAllCheck : false , check_list : [], datalist : [{ 'name' : '商品1' , 'price' : 10 , 'count' : 1 , }, { 'name' : '商品2' , 'price' : 20 , 'count' : 2 , }, { 'name' : '商品3' , 'price' : 30 , 'count' : 3 , }, ], }, methods : { getSum : function ( ) { var datas = this .check_list var res = 0 ; for (var i = 0 ; i < datas.length; i++) { res += datas[i].count * datas[i].price; } return res }, check_all : function ( ) { if (this .isAllCheck) { this .check_list = this .datalist; } else { this .check_list = []; } }, check_all2 : function ( ) { if (this .check_list.length === this .datalist.length) { this .isAllCheck = true ; } else { this .isAllCheck = false ; } } } }) </script >
fetch 有些浏览器自带支持Ajax请求的库 , 这个库就是fetch
1 2 3 fetch(地址).then(res => res.json()).then(res => { console .log(res) })
axios axios : 专门用于做AJax请求的库 .
axios 是一个基于Promise 用于浏览器和 node.js 的 HTTP 客户端,它本身具有以下特征:
从浏览器中创建 XMLHttpRequest
从 node.js 发出 http 请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
取消请求
自动转换JSON数据
客户端支持防止 CSRF/XSRF
API
axios.get(地址?key=value&key2=values).then(function(response), function(err){})
axios,post(地址,{key:value,key 2:value2}).then(function(response)), function(err){})
```js axios({ method: ‘get’, url: ‘http://bit.ly/2mTM3nY' , headers: “{‘name’:’hyl’}”, responseType: ‘stream’ }) .then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 4. ### 示例 ```html <div id="box"> <button class="btn btn-default" @click="getjoke">get joke</button> </div> <script> var vm = new Vue({ el: "#box", methods: { getjoke: function() { axios.get( 'https://autumnfish.cn/api/joke/list',{ params:{ num:2 } }).then(function(response){ console.log(response); },function(err){ console.log(err); }) } } }) </script>
注意:
axIos回调函数中的this已经改变 , 无法访问到vue的data中的数据
把this保存起来回调函数中直接使用保存的this即可
并发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function getUserAccount ( ) { return axios.get('/user/12345' ); } function getUserPermissions ( ) { return axios.get('/user/12345/permissions' ); } axios.all( [ getUserAccount(), getUserPermissions() ] ) .then(axios.spread(function (acct, perms ) { }) );
请求拦截器和响应拦截器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 axios.interceptors.request.use( function (config ) { return config; }, function (error ) { return Promise .reject(error); } ); axios.interceptors.response.use( function (config ) { return config; }, function (error ) { return Promise .reject(error); } );
Vue component 组件 : 封装了样式 , 标签 , js的 代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <div id ="box" > <navbar > </navbar > </div > <script type ="application/javascript" > Vue.component('navbar',{ template:` <div style ='background:yellow' > <button @click ='show' > 返回</button > 导航栏 <button > 主页</button > </div > `, methods:{ show:function(){ console.log('show'); } } }) </script > <script > var vm = new Vue({ el : "#box" , }) </script >
全局组件和局部组件
全局组件和局部组件 的关系 可以类比成python中全局变量和局部变量
的关系
全局组件 大家都可以访问 , 局部组件只有他的父亲才可以访问
Vue.component定义的是全局组件
局部组件使用components关键字定义
全局组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <script type ="application/javascript" > Vue.component('navbar',{ template:` <div style ='background:yellow' > <button @click ='show' > 返回</button > 导航栏 <button > 主页</button > <navbarchild > </navbarchild > </div > `, methods:{ show:function(){ console.log('show'); } } }) </script > <script type ="text/javascript" > Vue.component('navbarchild' ,{ template :`<h1>this is navbarchild</h1>` }) </script >
局部组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <script type ="application/javascript" > Vue.component('navbar',{ template:` <div style ='background:yellow' > <button @click ='show' > 返回</button > 导航栏 <button > 主页</button > <navbarchild > </navbarchild > </div > `, methods:{ show:function(){ console.log('show'); } }, components:{ 'navbarchild':{ template:`<h1 > this is navbarchild</h1 > `, } } }) </script > <script > var vm = new Vue({ el : "#box" , }) </script >
组件编写方式 和 Vue实例的区别
自定义组件需要有一个root element
父子组件的data是无法共享的
组件可以有data , methods , computed, 但是 data必须是一个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <script type ="application/javascript" > Vue.component('navbar',{ template:` <div style ='background:yellow' > <button @click ='show' > 返回</button > 导航栏 <button > {{ navarname }} 主页</button > <navbarchild > </navbarchild > </div > `, methods:{ show:function(){ console.log('show'); } }, data(){ return { navarname:'hyl', } }, components:{ 'navbarchild':{ template:`<h1 > this is navbarchild</h1 > `, } } }) </script >
父子通信 总结 :
props down
events up
父传子 props : 接收父组件传过来的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <div id ="box" > <navbar username ="hyl" > </navbar > <navbar username ="czj" > </navbar > <navbar :username ="parents" > </navbar > </div > <script type ="application/javascript" > Vue.component('navbar',{ template:` <div > <button > 返回</button > {{username }} 导航栏 <button > {{ navarname }} 主页</button > </div > `, props:['username'] }) </script > <script > var vm = new Vue({ el : "#box" , data :{ parents :'parents' } }) </script >
注意:
1 <navbar username ="hyl" > </navbar >
这样 , 传过去的hyl是string , 那么如果要传true
或false
呢?
使用动态绑定
1 <navbar :isshow ="true" > </navbar >
属性类型验证 1 props:['username','isShow']
改成
1 2 3 4 props:{ 'username':String, 'isShow':Boolean }
子传父 子传父 , 需要使用事件:
儿子分发(触发)事件 , 父亲接收事件 , 然后执行函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <div id ="box" > <navbar @myevent ="eventHandler" > </navbar > </div > <script type ="application/javascript" > Vue.component('navbar' ,{ template :` <div> <button @click="payMoney">click</button> </div>` , data ( ) { return { childname :"子组件的状态" } }, methods :{ payMoney ( ) { this .$emit("myevent" ,this .childname) } } }) </script > <script > var vm = new Vue({ el : "#box" , data :{ parents :'parents' }, methods :{ eventHandler (ev ) { console .log(ev) } } }) </script >
子传父示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <div id ="box" > <navbar @myevent ='eventHandler' > </navbar > <sidebar v-show ='isShow' > </sidebar > </div > <script type ="text/javascript" > Vue.component('navbar' ,{ template :` <div> <button type="button" @click="alarm">show</button> </div>` , data ( ) { return { isShow :true } }, methods :{ alarm ( ) { this .$emit("myevent" ) } } }) </script > <script type ="text/javascript" > Vue.component('sidebar', { template: ` <div style ='background:yellow; width:200px' > <ul > <li > </li > <li > </li > <li > </li > </ul > </div > ` }) </script > <script > var vm = new Vue({ el : "#box" , data : { isShow : true }, methods :{ eventHandler ( ) { this .isShow = !this .isShow } } }) </script >
ref通信
ref放在标签上 , 拿到的是原生节点
ref放在组件上 , 拿到的是组件对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <input type ="text" ref ='mytext' /> <button type ="button" @click ="handleAdd" > add</button > </div > <script > var vm = new Vue({ el : "#box" , methods : { handleAdd ( ) { console .log(1111 ,this .$refs.mytext.value) } }, }) </script >
既然能拿到组件对象 , 那么就能拿到组件的data数据 和 method方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <div id ="box" > <child ref ='mychild' > </child > <button type ="button" @click ="handleAdd" > add</button > </div > <script type ="text/javascript" > Vue.component('child' ,{ template :`<div> child </div>` , data ( ) { return { msg :'this is component msg' } }, methods :{ alarm ( ) { console .log('this is component method' ) } } }) </script > <script > var vm = new Vue({ el : "#box" , data : { }, methods : { handleAdd ( ) { console .log(1111 ,this .$refs.mychild.msg) this .$refs.mychild.alarm() } }, }) </script >
可见 , 父组件具有对子组件的绝对控制权
非父子通信 – 事件总线
兄弟之间的通讯其实可以通过父亲作为中介 : 儿子A -> 父亲 -> 儿子B
同理孙子之间的通讯可以通过祖父作为中介 : 孙子A -> 父亲A -> 祖父 -> 父亲B -> 孙子B
这样 , 我们就能抽象出一个事件总线 :
儿子A -> 事件总线 -> 儿子B
孙子A -> 事件总线 -> 孙子B
曾孙子A -> 事件总线 -> 曾孙子B
也就是说 , 事件总线相当于一个平台 , 用于沟通两个组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <div id ="box" > <server > </server > <client > </client > </div > <script type ="text/javascript" > var bus = new Vue() Vue.component('server' , { template : ` <div> <input type='text' ref='mytext'> <button @click='eventHandler'>server发布</button> </div>` , methods :{ eventHandler ( ) { bus.$emit('mymsg' ,this .$refs.mytext.value) } } }) Vue.component('client' , { template : ` <div>client</div>` , mounted ( ) { console .log('生命周期函数 , 当前组件的dom 创建渲染完成之后就会调用' ) bus.$on('mymsg' ,(data )=> {console .log('收到推送了' ,data)}) } }) </script > <script > var vm = new Vue({ el : "#box" , data : { isShow : true }, }) </script >
总结 :
1 2 3 4 5 6 7 8 9 10 var Event = new Vue(); Event.$emit('msg' ,this .msg); Event.$on('msg' ,function (msg ) { })
动态组件
<component>
标签 , 动态绑定组件到他的IS属性
<keep-alive>
标签 , 保留状态 , 避免重新渲染
1 2 <component is ='home' > </component >
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id ="box" > <li > <a @click ="who='home'" > home</a > <a @click ="who='list'" > list</a > <a @click ="who='cart'" > cart</a > </li > <component :is ="who" > </component > </div > <script > var vm = new Vue({ el : "#box" , data : { who :'home' }, components :{ 'home' :{template :`<div>home</div>` }, 'list' :{template :`<div>list</div>` }, 'cart' :{template :`<div>cart</div>` }, } }) </script >
需要注意的是 , <component>
在切换的时候 , 会干掉旧的标签 , 更换成新的标签
这时 , 我们就需要使用<keep-alive>
标签
我们将需要保留的标签使用<keep-alive>
标签包裹即可
1 2 3 <keep-alive > <component :is ="who" > </component > </keep-alive >
Vue-slot slot插槽 (内容分发)
单个slot
混合父组件的内容与子组件自己的模板 -> 内容分发
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
slot类似于jinja里的block , 用于插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id ="box" > <child > <div > 这是父组件插入子组件的div</div > </chilld > </div > <script type ="text/javascript" > Vue.component('child',{ template:`<div > child <slot > </slot > </div > ` }) </script > <script > var vm = new Vue({ el : "#box" , data : { isShow : true }, }) </script >
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <div id ="box" > <navbar @myevent ='eventHandler' > </navbar > <sidebar v-show ='isShow' > </sidebar > </div > <script type ="text/javascript" > Vue.component('navbar' ,{ template :` <div> <button type="button" @click="alarm">show</button> </div>` , data ( ) { return { isShow :true } }, methods :{ alarm ( ) { this .$emit("myevent" ) } } }) </script > <script type ="text/javascript" > Vue.component('sidebar', { template: ` <div style ='background:yellow; width:200px' > <ul > <li > </li > <li > </li > <li > </li > </ul > </div > ` }) </script > <script > var vm = new Vue({ el : "#box" , data : { isShow : true }, methods :{ eventHandler ( ) { this .isShow = !this .isShow } } }) </script >
将上面子传父
修改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <div id ="box" > <navbar > <button type ="button" @click ="isShow=!isShow" > show</button > </navbar > <sidebar v-show ='isShow' > </sidebar > </div > <script type ="text/javascript" > Vue.component('navbar', { template: ` <div > <slot > </slot > </div > ` }) </script > <script type ="text/javascript" > Vue.component('sidebar', { template: ` <div style ='background:yellow; width:200px' > <ul > <li > </li > <li > </li > <li > </li > </ul > </div > ` }) </script > <script > var vm = new Vue({ el : "#box" , data : { isShow : true }, }) </script >
具名slot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <div id ="box" > <child > <div slot ="header" > 这是父组件插入子组件的header</div > <div slot ="footer" > 这是父组件插入子组件的footer</div > </child > </div > <script type ="text/javascript" > Vue.component('child', { template: `<div > <slot name ="header" > 这是子组件的header</slot > <h1 > child</h1 > <slot name ="footer" > 这是子组件的footer</slot > </div > ` }) </script > <script > var vm = new Vue({ el : "#box" , }) </script >
transition过渡 vue在插入、更新或者移除DOM时,自动添加/删除 CSS 类名,以此来提供多种不同方式的应用过渡效果
单元素/组件过渡
CSS过渡
CSS动画
结合animate.css动画库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <style type ="text/css" > .myfade-enter-active , .myfade-leave-active { transition : all 1.5s ; } .myfade-enter , .myfade-leave-to { opacity : 0 ; transform : translateX (100px ); } .mybound-enter-active { animation : bounce-in .5s ; } .mybound-leave-active { animation : bounce-in .5s reverse; } @keyframes bounce-in { from { opacity : 0 ; transform : translateX (100px ); } to { opacity : 1 ; transform : translateX (0px ); } } </style > <div id ="box" > <button type ="button" @click ="isShow=!isShow" > button</button > <transition name ="myfade" > <div v-show ="isShow" > 11111111111 </div > </transition > <transition name ="mybound" > <div v-show ="isShow" > 2222222 </div > </transition > </div > <script > var vm = new Vue({ el : "#box" , }) </script >
单组件过渡同理
多个元素/组件过渡(需要设置key)
<transition>
can only be used on a single element. Use <transition-group>
for lists.
这里的多个元素
, 是指多个互斥元素
, 是if-elif-else , 只能有一个
多个能通知存在的元素 , 称为列表元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <button type ="button" @click ="isShow=!isShow" > button</button > <transition name ="myfade" > <div v-if ="isShow" > 11111111111</div > <div v-else > 222222</div > </transition > </div > <script > var vm = new Vue({ el : "#box" , data :{ isShow :true , } }) </script >
上面的代码并不会触发动画 , 因为Vue的重用机制导致的 , 并不是真的删除<div v-if="isShow">11111111111</div>
, 然后再创建 <div v-else>222222</div>
, 而是直接修改innerHTML
当有相同标签名的元素切换时,需要通过key特性设置唯一的值来标记以让Vue区分它们,否则Vue为了效率只会替换相同标签内部的内容。
所以需要修改成
1 2 <div v-if ="isShow" key ='1' > 11111111111</div > <div v-else key ='2' > 222222</div >
过渡动画模式 (默认同时执行 in 和 out)
1 2 3 4 <transition name ="myfade" mode ="in-out" > <transition name ="myfade" mode ="out-in" >
多个组件过渡同理
1 2 3 4 5 <keep-alive > <transition name ='bounce' > <component :is ="who" > </component > </transition > </keep-alive >
列表过渡(需要设置key) < transition-group>
不同于 transition,它会以一个真实元素呈现:默认为一个<span>
。 你也可以通过tag特性更换为其他元素。
1 2 3 4 5 6 7 8 <ul > <transition-group tag ="ul" name ="mybounce" > <li v-for ='(data,idx) in datalist' :key ='data' > {{data}} -- {{idx}} <button type ="button" @click ="del(idx)" > del</button > </li > </transition-group > </ul >
Vue 生命周期钩子 选项 / 生命周期钩子API
全部钩子
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <script type ="text/javascript" > var vm = new Vue({ el : "#app" , data : { msg : "hi vue" , }, beforeCreate :function ( ) { console .log('beforeCreate' ); }, created :function ( ) { console .log('created' ); }, beforeMount : function ( ) { console .log('beforeMount' ); }, mounted : function ( ) { console .log('mounted' ); }, beforeUpdate : function ( ) { console .log('beforeUpdate' ); }, updated : function ( ) { console .log('updated' ); } }); setTimeout (function ( ) { vm.msg = "change ......" ; }, 3000 ); </script >
过滤器 类似于jinja , 也是使用管道符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="box" > <p :title ="name | myupper" > p标签</p > </div > <script > Vue.filter('myupper' ,function (str ) { return str + ' is sb' ; }) var vm = new Vue({ el : "#box" , data : { name : 'hyl' }, }) </script >
自定义指令 为什么自定义指令 : 操作底层DOM
无参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id ="box" > <p v-hello > p标签</p > </div > <script > Vue.directive('hello' ,{ inserted (el ) { console .log('当前节点插入到父节点了' ,el) } }) var vm = new Vue({ el : "#box" , }) </script >
带参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div id ="box" > <p v-hello ="'red'" > p标签</p > </div > <script > Vue.directive('hello' ,{ inserted (el,bind ) { console .log('当前节点插入到父节点了' ,el) console .log('传入的参数值为' ,bind.value) el.style.background=bind.value }, update (el,bind ) { el.style.background=bind.value } }) var vm = new Vue({ el : "#box" , data : { name : 'hyl' }, }) </script >
注意 : 指令只能接收一个参数
但是我们可以传入一个对象作为 , 变相传入多个参数
自定义指令的生命周期
bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个绑定时执行一次的初始化动作。
inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)。
update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
unbind:只调用一次,指令与元素解绑时调用。