VUE框架(一)
一、VUE環境搭建
1.1、下載開發版本的Vue
開發版本:https://cn.vuejs.org/js/vue.js
生產版本:https://cn.vuejs.org/js/vue.min.js
1、下載完畢后引入
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="../js/vue.js"></script> </head>1.2、安裝開發者工具
谷歌應用商店直接下載:Vue.js devtools
https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd
安裝完畢后查看:
?1.3、關閉vue在啟動時生成的生產環境提示
<script type="text/javascript"> Vue.config.productionTip = false // 阻止vue在啟動時生成的生產環境提示 </script>在瀏覽器上檢查
二、寫一個 hello world
<body><!--準備一個容器--> <div id="root"><h1>hello: {{name}},{{age}}</h1><!-- {{}} 模板選擇器,讀取data里面的數據 --> </div><script type="text/javascript"> // 阻止vue在啟動時生成的生產環境提示 Vue.config.productionTip = false// 創建Vue實例 const x = new Vue({el: "#root", // 綁定id="root"的容器,值通常為css選擇器字符串 (CSS里面的ID選擇器)data:{ // data里面存儲的數據,給'el'指定的容器使用name: "wdl",age:18} }) </script></body># 執行結果:hello: wdl,182.1、總結下這個簡單的代碼
????1、想讓Vue工作,就必須創建一個vue實例,并且傳入一個配置對象(el和data)
????2、root容器的代碼依然符合html規范,只不過混入了一些特殊的Vue語法
????3、root容器里的代碼被稱為(Vue模板)
? ? ?
三、延伸一下
3.1、在div容器內{{}}里面除了寫vue的data里面的,還可以寫js表達式
<body><!-- 容器 --> <div id="root"><!-- 這里面寫js表達式(a,a+b,demo(1)這種) 和 js代碼(if(){},for(){}這種) --><h1>1,{{name}},{{addr.toUpperCase()}},{{1 + 1}}</h1><!--addr.toUpperCase() 字符串大寫addr.toLowerCase() 字符串小寫--> </div><script type="text/javascript"> Vue.config.productionTip = false // 阻止vue在啟動時生成的生產環境提示// 創建Vue實例 new Vue({el: '#root', // el 指定當前實例為哪個容器服務,值通常為CSS里面的選擇器data: { // 用于存儲數據,給el指定的容器'#root'使用。name: 'sudada',addr: 'shanghai',}, })</script></body># 執行結果:1,sudada,SHANGHAI,23.2、總結下
? ? 1、Vue實例和容器是一一對應的。
? ? 2、真是開發中只有一個Vue實例,并且會配合著組件一起使用。
? ? 3、一旦data中的數據發生改變,那么模板中用到改數據的地方也會自動更新。
? ? 4、{{xxx}}中的xxx要寫js表達式,且xxx可以自動讀取到data中的所有屬性
四、模板語法
4.1、插值語法和指令語法(v-xxx)
<body><div id="root"><h1>插值語法</h1><!--插值語法:一般用于解析標簽體內容--><h3>hello,{{name}}</h3><h1>指令語法</h1><!--指令語法:一般用于解析標簽(格式為:v-xxx)--><h1>奧術{{name}}大師</h1><a :href="url">百度</a><a :href="school.url">點我去學校{{school.name}}學習</a></div></body><script type="text/javascript">Vue.config.productionTip = falsenew Vue ({el:'#root',data:{name:'jack',url:'http://www.baidu.com',school:{name:"sudada",url:'http://www.sougou.com'}}}) </script>4.2、總結插值語法和指令語法
??1、插值語法:一般用于解析"標簽體"內容(<h1>xxx</h1>,這個標簽了里面的"xxx"就是標簽體)
????寫法:{{xxxx}},xxxx是js表達式,且可以直接讀取到data中的所有屬性
??2、指令語法:格式為?"v-xxx"?一般用于解析"標簽"?(包含標簽屬性,標簽內容,綁定事件等)(<a?:href="school.url"?x="hello">,這里面的":href"和x="hello"就是標簽屬性?)
????寫法:v-bind:href="xxx"?簡寫為?:href="xxx","xxx"會被當做js表達式執行,可以直接讀取到data中的所有屬性。
五、數據綁定
5.1、單向、雙向數據綁定
<body><div id="root"><h1>{{name}}</h1>單向數據綁定: <input type="text" :value="name"><br>雙向數據綁定: <input type="text" v-model="name"><br><!--錯誤代碼示例,如下,因為v-model只能應用在"表單"類元素(輸入類元素,如上)--><h2 v-model:x="name">hello</h2></div> </body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el:"#root",data:{name:"wdl",input_value:"xxx"}}) </script>5.2、單向、雙向數據綁定總結
??單向數據綁定(只針對表單input輸入類,input輸入的值就是value):v-bind:value="name",里面的'value'會去讀"name"的值,當修改'value'的值時,"name"的值不會改變。只能讀不能改
??雙向數據綁定(只針對表單input輸入類,input輸入的值就是value):v-model:value="name",里面的'value'會去讀"name"的值,當修改'value'的值時,"name"的值也會跟著改變。可讀可改寫。
????v-model:value?可以簡寫為:v-model,因為v-model默認收集的就是value值。
??數據綁定簡寫:
??????單向數據綁定:?<input?type="text"?:value="name"><br>
??????雙向數據綁定:?<input?type="text"?v-model="name"><br>
六、el和data的兩種寫法
<body><div id="root"><h1>hello,{{name}}</h1> </div><script type="text/javascript">// 一、el 的2種寫法(2種方式皆可正常使用)// el 方法:把vue實例對象綁定(掛載)到容器(定義時就指定綁定哪個容器 )new Vue({el:"#root",data:{name:"111",}})// $mount 方法:把vue實例對象,綁定(掛載)到容器(最后在指定綁定哪個容器)const v = new Vue({data:{name:"222",}})console.log(v)v.$mount("#root")// 二、data 的2種寫法new Vue({el: "#root",// data的第一種寫法:對象式data: {name: "sudada",},// data的第二種寫法:函數式(不能寫成"=>"函數。data函數必須要返回一個數據,這個返回的數據,就是容器內用到的數據。比如容器內用的是name,那么這里就要return一個name)data(){ // 普通函數,原生寫法:data:functionconsole.log(this) // 此處的this是vue實例對象(這里的this就等于"const v = new Vue"的v)return{name: "szq"}}}) </script>七、MVVM模型
7.1、MVVM模型圖解
MVVM模型:
??1、M:模型(Model):data中的數據
??2、V:?視圖(View):頁面模板(DOM)
??3、VM:視圖模型(ViewModel):Vue實例,簡稱vm
觀察發現:
??1、data對象中的所有屬性(值),最后都出現在了vm身上。(可以通過vm.xxx拿到data對象里面xxx的值)
??2、vm身上的所有屬性以及Vue原型上所有屬性,在Vue模板中都可以直接使用。(vm?這個變量名就表示了Vue實例對象)
?7.2、用法說明
<body> <!-- View 模型 --><div id="root"><h1>學校:{{name}}</h1><h1>地址:{{addr}}</h1><h1>1:{{$options}}</h1><!-- $options:vm身上的屬性,這里直接可以調用(僅做測試,目的是證明"模板"里面可以直接調用vm的所有屬性) --></div> </body><script type="text/javascript">Vue.config.productionTip = false// ViewModel模型,簡稱vm(vm 這個變量名就表示了Vue實例對象)const vm = new Vue({el:"#root",// Model 模型data:{name:"sudada",addr:"shanghai",}})console.log(vm)console.log(vm.name) </script>八、Vue中的數據代理
8.1、原理與實現
1、Vue中的數據代理:是通過vm對象中屬性的操作(讀/寫)
2、Vue中數據代理的好處:更加方便的操作data中的數據
3、基本原理:
??通過Object.defineProperty()把data對象中所有屬性添加到vm上。
??為每一個添加到vm的屬性,都指定一個"getter/setter"。
??在"getter/setter"內部去操作(讀/寫)data中對應的屬性。
4、實踐證明:
??console.log(vm.name):獲取的是data里面name屬性的值,實際上調用的是Vue的"get?name"方法實現的。
??console.log(vm.name="szq"):修改的是data里面name屬性的值,實際上調用的是Vue的"set?name"方法實現的。
5、vm如何獲取data對應的值,使用vm._data,返回的值是是一個對象。(vm._data?==?options.data?==?data)
8.2、數據代理圖示?
九、事件處理
9.1、綁定事件(鼠標點擊/單擊時觸發)
????1、綁定事件v-on:click?簡寫為?@click
????2、綁定事件觸發的函數要寫到methods里面,不建議寫到data里面
9.2.1、綁定事件總結
? 1、使用v-on:xxx?或者?@xxx?綁定事件,其中"xxx"是事件名
? 2、事件的回調需要配置在methods對象中,最終會在vm上
? 3、methods配置的函數,不需要用箭頭函數,否則this就不是vm了
? 4、methods配置的函數,都是被Vue所管理的函數,this的指向是vm或者組件實例對象
? 5、@click="showInfo1"?和?@click="showInfo2($event,66)"效果一樣,但是后者可以傳參。
9.2、事件的修飾符
? 事件修飾符可以連著寫:@click.prevent.stop? 先阻止默認事件,再阻止事件冒泡
? 1、@click.prevent?阻止默認事件(常用)
??2、@click.stop?阻止事件冒泡(常用)
??3、@click.once?事件只觸發一次(常用)
??4、@click.capture?使用事件的捕捉模式
??5、@click.self?只有event.target是當前操作的元素時才觸發時間
??6、@click.passive?事件的默認行為立即執行,無需等待事件回調執行完畢
9.2.1、事件處理是先捕獲,在冒泡。
??捕獲階段:由外往內
??冒泡階段:由內往外
9.2.2、代碼示例
<body><style>/* 通配符,所有元素之間都有20px的間距*/*{margin-top:20px;}.demo1{width: 115px;height: 110px;float: left;margin: 7px;background-color: red;}.box1{padding: 5px;background-color: aqua;}.box2{padding: 5px;background-color: rosybrown;} </style><div id="root"><!-- 常用@click.prevent(事件修飾符): 阻止默認行為,也就是點擊后,只有彈窗,沒有a標簽的URL跳轉--><a href="https://www.baidu.com" @click.prevent="showinfo">點我跳轉</a><!-- 常用@click.stop:阻止事件冒泡,也就是點擊后只觸發一次alert提示。否則會有多次alert提示--><div class="demo1" @click="showinfo"><!-- 這里加@click.stop之后,里面的button被點擊時就不會觸發"alert" --><button @click.stop="showinfo">點我提示2</button></div><!-- 常用@click.once:事件只觸發一次alert提示,下次點擊就不會在觸發alert提示了。--><button @click.once="showinfo">點我提示3</button><!-- 不常用 @click.capture:使用事件的捕捉模式--><div class="box1" @click.capture="showmsg(1)">div1<div class="box2" @click="showmsg(2)">div2</div></div><!-- 不常用 @click.self:只有event.target是當前操作的元素時才觸發時間--><div class="demo1" @click.self="showinfo"><button @click="showinfo">點我提示4</button></div></div></body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el:"#root",data:{name:"sudada",addr:"shanghai",},methods:{showinfo(e){// e.preventDefault(); // 阻止默認行為,需要在函數內接收參數"e"// e.stopPropagation(); // 阻止事件冒泡,需要在函數內接收參數"e"alert("同學你好")},showmsg(msg){console.log(msg)}}}) </script>9.3、鍵盤事件
9.3.1、總結鍵盤事件
????keyup:任意鍵盤"按下去然后松手"就會觸發
????keydown:任意鍵盤"按下去"就會觸發
1)、Vue常見的按鍵別名:
????????回車鍵:@keyup.enter
????????刪除鍵:@keyup.delete(退格鍵和delete鍵都能觸發)
????????退出鍵:@keyup.esc
????????空格鍵:@keyup.space
????????換行鍵:@keyup.tab(這個鍵比較特殊,需要使用:@keydown.tab,使用@keyup.tab會和"tab鍵"本身的功能有沖突)
????????上鍵:@keyup.up
????????下鍵:@keyup.down
????????左鍵:@keyup.left
????????右鍵:@keyup.right
2)、系統修飾鍵(特殊用法):@keyup.ctrl,@keyup.alt,@keyup.shift,@keyup.meta
????????配合@keydown使用:正常觸發
????????配合@keyup使用:按下修飾鍵的同時,在按下其他鍵,隨后釋放其他鍵,時間才會觸發。
9.3.2、鍵盤事件示例
<body><div id="root"><h1>hello,{{name}}</h1><!--keyup:任意鍵盤"按下去然后松手"就會觸發keydown:任意鍵盤"按下去"就會觸發Vue常見的按鍵別名:回車鍵:@keyup.enter刪除鍵:@keyup.delete(退格鍵和delete鍵都能觸發)退出鍵:@keyup.esc空格鍵:@keyup.space換行鍵:@keyup.tab(這個鍵比較特殊,需要使用:@keydown.tab,使用@keyup.tab會和"tab鍵"本身的功能有沖突)上鍵:@keyup.up下鍵:@keyup.down左鍵:@keyup.left右鍵:@keyup.right系統修飾鍵(特殊用法):@keyup.ctrl,@keyup.alt,@keyup.shift,@keyup.meta配合@keydown使用:正常觸發配合@keyup使用:按下修飾鍵的同時,在按下其他鍵,隨后釋放其他鍵,時間才會觸發。--><!--@keyup.enter:在input框內輸入內容,只有按下"回車"鍵后,才能拿到input框內所有的內容。如果寫成@keyup="showinfo",那么輸入一行就拿到一行,拿到的內容就不完整(有多余的)--><input type="text" @keydown.tab="showinfo"> </div></body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{name:"szq"},methods:{showinfo(e){// e 就是event,默認傳遞的事件對象// e.target.value 拿到的就是input框內輸入的值console.log(e.target.value)}}}) </script>十、計算屬性
什么是屬性 Property ?
data(對象) 里面定義的值,都是屬性,都可以使用?{{?屬性?}} 直接解析到?屬性的值。
data:{firstname:"蘇",lastname:"三", },什么是方法?method ?
fullname?這個函數就是一個方法,可以使用?{{?fullname()?}}?直接拿到?方法的返回值。
methods:{fullname(){return this.firstname + "-" + this.lastname} }10.1、什么是計算屬性?
計算屬性是單獨定義的屬性(格式和data一樣),是一個全新的配置項 "computed"。
計算屬性總結:先拿到現有的屬性(a,b),然后做一次加工(a+b),最后生成一個全新的屬性(a+b=c,c這個屬性就是計算屬性)
1、定義:要用的屬性c不存在,要通過"已有的屬性a,b","計算a+b=c"得來的。
2、原理:底層借助了Object.defineproperty方法提供getter和setter。
3、get函數什么時候執行?(計算屬性什么時候執行?)
??初次讀取時會執行一次;
??當計算屬性內"任何一個被依賴的數據"發生"改變"時,計算屬性會被再次執行。
4、優勢:與methods實現相比,內部有"緩存機制(可以復用)",效率更高,調試方便。
5、備注:
??計算屬性最終會出現在vm上,直接讀取使用即可:this.xxx。
??如果計算屬性要被修改,那必須寫"set函數"去響應修改,且"set函數"要對原屬性a或者b的值做修改,修改的值就是"set函數"傳入的值。
10.2、代碼示例
<body> <div id="root">姓:<input type="text" v-model="firstname"> <br>名:<input type="text" v-model="lastname"> <br>全名: <span>{{fullname}}</span> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{firstname:"su",lastname:"dada",},// 計算屬性 computedcomputed:{// 把計算過程配置成一個對象fullname:{// 讀fullname時,執行get函數,并返回值// get什么時候調用?// 1.初次讀取fullname時// 2.所依賴的數據(this.firstname或者this.lastname)發生變化時。get(){console.log('get被調用')return this.firstname + "-" + this.lastname},// 當fullname被修改時,那么執行set函數// value 就是被修改后收到的值,比如把 fullname="張-三"修改為 fullname="李-四",那么"value"的值就是"李-四"set(value){console.log('set被調用', value)// 把收到的value的值,做拆分const arr = value.split('-')// 姓就是數組的第一個值this.firstname = arr[0]// 名就是數組的第二個值this.lastname = arr[1]}}}}) </script>10.3、計算屬性簡寫(只有在不寫set的情況下才能使用簡寫方式,如果有set的話,不能簡寫。)
<body><div id="root">姓:<input type="text" v-model="firstname"> <br>名:<input type="text" v-model="lastname"> <br>全名: <span>{{fullname}}</span> </div></body><script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({el:"#root",data:{firstname:"su",lastname:"dada",},// 計算屬性 computedcomputed:{// 這里的函數"fullname",就是計算屬性的名稱,這個函數和"getter函數"寫法一致。fullname(){console.log("get發生了調用")return this.firstname + '-' + this.lastname}} }) </script>十一、監視屬性
?11.1、監視屬性watch總結
? 1、當"被監視"的屬性發生變化時,"回調函數handler"自動調用,進行相關操作
? 2、"被監視"的屬性必須存在,才能進行監視
? 3、監視屬性的2種寫法:
? ? 1. new Vue 時傳入watch配置
? ? 2. 通過 vm.$watch 監視
11.2、監視屬性,代碼示例
<body> <div id="root"><h2>今天天氣很{{info}}</h2><button @click="changeweather">切換天氣</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{isHot: true,},computed:{info(){return this.isHot ? "炎熱" : "涼爽"}},methods:{changeweather(){this.isHot = !this.isHot}},// 監視方法一(2選1):watch:{// 使用watch方法,監測一個數據,這里是"isHot"isHot:{// 初始化時讓handler調用一下。immediate:true,// 當 isHot 發生改變時,handler被調用。// oldValue 修改前的值// newValue 修改后的值handler(newValue,oldValue){console.log("isHot被修改了",newValue,oldValue)},}}})// 監視方法二(2選1):// vm.$watch("isHot",{// immediate:true,// handler(newValue,oldValue){// console.log("isHot被修改了",newValue,oldValue)// },// }) </script>11.3、深度監視(舉例說明)
? ? 1.Vue中的watch默認不監測"對象內部值"的改變? ?(詳見:11.3.1)
? ? 2.配置的"deep:true"可以監測"對象內部值"改變? ? ?(詳見:11.3.2)
? ? 3.備注:
? ? ? ? 1.Vue自身可以監測對象內部值的改變,但Vue提供的watch默認不可以。
? ? ? ? 2.使用watch時可以根據數據的具體結構,決定是否采用深度監視(deep:true)。
11.3.1、Vue中的watch默認不監測"對象內部值"的改變
例子1:當numbers屬性值是numbers:{a=1,b=2},numbers.a發生改變時,watch是不監測的,handler函數不會執行。
<body> <div id="root"><h3>a的值是:{{numbers.a}}</h3><button @click=numbers.a++>點我a++</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{numbers:{a:1}},watch:{// 使用watch方法,監測numbers屬性numbers:{handler(newValue,oldValue){console.log("numbers被修改了",newValue,oldValue)}}}})</script>例子2:當numbers屬性值是numbers:true,此時當numbers的值發生改變(numbers=false)時,watch是監測的,handler函數會執行。
<body> <div id="root"><h3>a的值是:{{numbers}}</h3><button @click=numbers=!numbers>點我修改a</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{numbers:true},watch:{// 使用watch方法,監測numbers屬性numbers:{handler(newValue,oldValue){console.log("numbers被修改了",newValue,oldValue)}}}})</script>11.3.2、配置"deep:true"時,watch可以監測"對象內部值"改變
當numbers屬性值是numbers:{a=1,b=2},numbers.a發生改變時,watch是監測的,handler函數會執行。
<body> <div id="root"><h3>a的值是:{{numbers.a}}</h3><button @click=numbers.a++>點我a++</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{numbers: {a:1,b:2}},watch:{// 使用watch方法,監測numbers屬性numbers:{deep:true,handler(newValue,oldValue){console.log("numbers被修改了",newValue,oldValue)}}}}) </script>11.3.3、watch監視多級結構中"某個屬性"的變化
當numbers屬性值是numbers:{a=1,b=2},numbers.a發生改變時,或者numbers.b發生改變時,watch是能監測到的,handler函數會執行。
<body> <div id="root"><h3>a的值是:{{numbers.a}}</h3><button @click=numbers.a++>點我a++</button><hr/><h3>b的值是:{{numbers.b}}</h3><button @click=numbers.b++>點我b++</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{numbers: {a:1,b:2}},watch:{// 監視多級結構中某個屬性的變化,這里監視的是"numbers.a""numbers.a":{handler(newValue,oldValue){console.log("numbers.a被修改了",newValue,oldValue)},},// 監視多級結構中某個屬性的變化,這里監視的是"numbers.b""numbers.b":{handler(newValue,oldValue){console.log("numbers.b被修改了",newValue,oldValue)},},}}) </script>11.4、監視屬性的簡寫(當對象里面只有 handler 時,就可以使用簡寫了。就不能配置 "immediate:true" 和 "deep:true")
<body> <div id="root"><h3>a的值是:{{numbers}}</h3><button @click=numbers=!numbers>點我修改a</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{numbers: true},watch:{// 簡寫:當對象里面只有 handler 時,就可以使用簡寫了。就不能配置 "immediate:true" 和 "deep:true"numbers(newValue,oldValue){console.log("numbers被修改了",newValue,oldValue)}}})// 簡寫:就不能配置 "immediate:true" 和 "deep:true"// vm.$watch("isHot",function (newValue,oldValue){// console.log("isHot被修改了",newValue,oldValue)// }) </script>11.5、計算屬性和監視屬性的區分
computed和watch的區別:
? 1.computed能完成的功能,watch都可以完成,
? 2.watch能完成的功能,computed不一定能完成,比如watch可以進行異步操作。
2個重要的小原則:
? 1.所有被Vue管理的函數,最好寫成普通函數,這樣this的指向才是vm 或者 實例對象
? 2.所有不被Vue管理的函數(定時器的回調函數,ajax的回調函數等),最好寫成箭頭函數,這樣this的指向才是vm 或 組件實例對象。
十二、綁定樣式(不變的樣式寫死,變化的樣式使用":class"動態綁定)
12.1、綁定樣式寫法說明
? 1.class 樣式(常用)
? ? 寫法::class="xxx",xxx可以是字符串,對象,數組
? ? ? 字符串寫法,適用于:樣式的類名不確定,需要動態指定。
? ? ? 數組寫法,適用于:要綁定的樣式個數不確定,名字也不確定。
? ? ? 對象寫法,適用于:要綁定的樣式個數確定,名字也確定,但要動態決定是否使用。
? 2.style 樣式(不常用)
? ? :style="{fontSize: xxx}" 其中xxx是動態值。
? ? :style="xxx" ?其中xxx是樣式對象。
12.2、綁定樣式例子
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="../js/vue.js"></script><style>.normal{color: red;font-size: 15px;margin-left: 25px;}.happy {color: yellow;font-size: 10px;text-decoration: line-through;margin-left: 10px;}.nohappy{color: green;font-size: 10px;text-decoration: line-through;margin-left: 10px;}</style> </head><body> <div id="root"><!-- 綁定class樣式,字符串寫法,適用于:樣式的類名不確定,需要動態指定。--><div class=normal :class=mood @click=changemood>{{name}}</div> <br/><!-- 綁定class樣式,數組寫法,適用于:要綁定的樣式個數不確定,名字也不確定--><div class=normal :class=classarr @click=changemood>{{name}}</div> <br/><!-- 綁定class樣式,對象寫法,適用于:要綁定的樣式個數確定,名字也確定,但要動態決定是否使用--><div class=normal :class=classobj> {{name}} </div> <br/><!-- 綁定style樣式,對象寫法--><div class=normal :style=styleobj> {{name}} </div> <br/> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{name:"sudada",// 字符串寫法mood:"normal",// 數組寫法classarr:["nohappy","happy"],// 對象寫法classobj:{normal:false, // 為false默認不使用, 為true時使用happy:true},// 綁定style樣式,對象寫法styleobj:{fontSize:"40px", // fontSize 為固定寫法,是font-size的意思(顯示字體大小的格式)color:"yellow", // 字體顏色(單個字段)}},methods:{// 字符串寫法例子changemood(){this.mood = "happy"},}}) </script>十三、列表渲染(符合某些條件,做對應的渲染)
13.1、v-show使用
? ? 寫法:v-show="表達式"
? ? 適用于:切換頻率較高的場景
? ? 特點:不展示的dom元素未被移出,僅僅是是使用樣式隱藏掉。
13.2、v-if使用
? ? 適用于:切換頻率較低的場景
? ? 特點:不展示dom元素,直接刪除
? ? 注意:v-if可以和v-else-if,v-else 一起使用,但要求結構不能被"打斷"
十四、列表渲染
14.1、v-for循環遍歷
<body> <div id="root"><h2>人員列表</h2><ul><!-- for循環遍歷"數組"類型:(p,index) in persons,其中:"p"就是for循環"persons(數組類型)"的一行行數據,"index"就是"persons"的索引值(0,1,2,xxx),:key="index",綁定索引值 --><li v-for="(p,index) in persons" :key="index">{{p.name}}-{{p.age}}</li></ul><ul><!-- for循環遍歷"對象"類型:v-for="(v,k) in car",其中"v"就是對象的value,k"就是對象的key,:key="k",綁定對象的key --><li v-for="(v,k) in car" :key="k">{{v}}--{{k}}</ul><ul><!-- for循環遍歷"字符串"類型:v-for="(s,index) in str",其中"s"就是字符串的一個個字符,"index"就是字符串的索引,:key="index",綁定索引值 --><li v-for="(s,index) in str" :key="index">{{s}}--{{index}}</ul> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{persons:[{id:'001',name:'zhangsan',age:19},{id:'002',name:'lisi',age:29},{id:'003',name:'wangwu',age:39},],car:{name:"adA8",price:"80W",color:"black",},str:"hello"}}) </script>14.1.1、v-for循環遍歷,":key"的作用與原理
1、虛擬DOM中key的作用
? key是虛擬DOM對象的標識,當數據發生變化時,Vue會根據"新數據"生成"新的虛擬DOM",隨后Vue進行"新的虛擬DOM"與"舊的虛擬DOM"的差異比較,比較規則如下:
2、對比規則
? 1.舊虛擬DOM中找到了與新虛擬DOM相同的key
? ? 若虛擬DOM中內容沒變,直接使用之前的真實DOM。
? ? 若虛擬DOM中內容變了,則生成新的真實DOM,隨后替換掉頁面中之前的真實DOM。
? 2.舊虛擬DOM中未找到與新虛擬DOM相同的key
? ? 創建新的真實DOM,隨后渲染到頁面
3、開發中如何選擇:
? 1.最好使用每行數據的"唯一標識"作為key。
? 2.如果不需要對數據做"逆序添加"(this.persons.unshift(p)),"逆序刪除"等"破壞順序"的操作時,使用index作為Key沒有問題。
14.2、input框內的模糊搜索
14.2.1、計算屬性實現
<body> <div id="root"><h2>人員列表</h2><input type="text" placeholder="請輸入名字" v-model="keword"><!-- 計算屬性實現 --><ul><li v-for="(p,index) in filpersons" :key="index">{{p.name}}--{{p.age}}--{{p.sex}}</li></ul> </div> </body><script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({el:"#root",data: {keword:"",persons: [{id: "001", name: "馬冬梅", age: 18, sex: "女"},{id: "002", name: "周冬雨", age: 28, sex: "女"},{id: "003", name: "周杰倫", age: 38, sex: "男"},{id: "004", name: "溫兆倫", age: 48, sex: "男"},],},// 計算屬性實現computed:{filpersons(){return this.persons.filter((p)=>{// indexOf(val) == -1 說明沒匹配到,等于其他"0,1,2,xxx"表示匹配數據的索引值。// 這里依賴的數據是:"this.keword",也就是當"this.keword"發生改變,計算屬性就會被執行。return p.name.indexOf(this.keword) !== -1})},} }) </script>14.2.2、監視屬性實現
<body> <div id="root"><h2>人員列表</h2><input type="text" placeholder="請輸入名字" v-model="keword"><!-- 監視屬性實現 --><ul><li v-for="(p,index) in filpersons" :key="index">{{p.name}}--{{p.age}}--{{p.sex}}</li></ul> </div> </body><script type="text/javascript"> Vue.config.productionTip = false// 監視屬性實現 const vm = new Vue({el:"#root",data: {keword:"",persons: [{id: "001", name: "馬冬梅", age: 18, sex: "女"},{id: "002", name: "周冬雨", age: 28, sex: "女"},{id: "003", name: "周杰倫", age: 38, sex: "男"},{id: "004", name: "溫兆倫", age: 48, sex: "男"},],// 存放過濾后的數據filpersons:[]},watch:{// val 接收input框內輸入的值keword:{// 初始化時讓handler調用一下。immediate:true,handler(val){// filter方法:"p"就是"persons"里面的一行行數據。// 如果"val"的值為'空'時,使用"filter方法"就能拿到的就是"persons"里面所有的數據。this.filpersons = this.persons.filter((p)=>{// indexOf(val) == -1 說明沒匹配到,等于其他"0,1,2,xxx"表示匹配數據的索引值。return p.name.indexOf(val) !== -1})}},} }) </script>14.3、input框內數據排序(升降序)
<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> <br/><li v-for="(p,index) in filepersons" :key="index">{{p.name}}-{{p.age}}-{{p.sex}}-{{p.status}}</li></ul> </div> </body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el: "#root",data: {keyWord: "",// 0原順序,1降序,2升序sortType:0,persons: [{id:"001",name:"馬冬梅",age:48,sex:"女"},{id:"002",name:"周冬雨",age:38,sex:"女"},{id:"003",name:"周杰倫",age:18,sex:"男"},{id:"004",name:"溫兆倫",age:58,sex:"男"},]},computed:{filepersons(){// 先過濾(拿到過濾后的數據arry)const arry = this.persons.filter((p) => {return p.name.indexOf(this.keyWord) !== -1})// 然后對arry做判斷是否需要排序(后排序)if (this.sortType){// this.sortType = 1 或者 2 時,按年齡排序(升序或者降序)arry.sort((a,b)=>{return this.sortType === 1 ? b.age-a.age : a.age-b.age})}// 如果this.sortType=0,就返回原值或者過濾后的值(無排序)// 如果this.sortType=1或者2,就返回原值或者過濾后的值(外加排序)return arry}}}) </script>14.4、Vue監測數據的原理(通過Vue.set或者vm.$set)
14.4.1、例子,Vue.set:可以在"對象{}"內新增一個屬性(這個屬性之前是未定義的)
Vue.set:不能直接給data直接添加屬性,只能給data里面的某一個對象,比如data.xxx添加屬性。
<body> <div id="root"><h2>姓名{{student.name}}</h2><h2>年齡{{student.age}}</h2><h2 v-if="student.sex">性別{{student.sex}}</h2><button @click="addsex">點我添加性別屬性</button><ul><h2>愛好</h2><li v-for="(h,index) in student.hoppy" :key="index">{{h}}</li><h2>朋友們</h2><li v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}---{{f.sex}}</li></ul> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{name:"zzz",addr:"shanghai",student:{name:"sudada",age:18,hoppy:["抽煙","喝酒","燙頭"],}},methods:{addsex(){// Vue.set:不能直接給data直接添加屬性,只能給data里面的某一個對象,比如data.xxx添加屬性。// 給data內的某一個對象添加一個"屬性",添加完畢后這個"屬性"就可以被調用了。以下兩種方法 2選一// Vue.set(this.student,"sex","男") // 方法一 (給"student"對象添加一個"sex"屬性,屬性值是"男")// Vue.set(this.student.hoppy,1,"打游戲") // 方法一 (給"student"對象添加一個"hoppy"屬性,屬性值是"打游戲")vm.$set(this.student,"sex","男") // 方法二 (給"student"對象添加一個"sex"屬性,屬性值是"男")}}}) </script>14.4.2、直接對數組內的某個索引做"賦值替換",Vue是不生效的,例子如下:
直接對數組內的某個索引做"賦值替換",Vue是不生效的:
如果要修改數組內的某個索引對應的值(對象)的屬性,Vue是生效的:
如果使用官方推薦的,數組的7種修改方法:(push末尾行追加,pop末尾行刪除,unshift首行追加,shift首行刪除,splice數組內某個元素替換,sort排序,reverse反轉數組)修改,Vue是生效的。
<body> <div id="root"><h2>姓名:{{name}}</h2><h2>朋友</h2><button @click="addfriend">添加一個朋友</button><ul><li v-for="(f,index) in friends" :key="index">{{f}}</li></ul> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{name:"szq",friends:[{name:"szq",age:28,sex:"男"},]},methods:{addfriend(){// 直接對數組內的某個索引做"賦值替換",Vue是不生效的// this.friends[0]={name:"sudada",age:18,sex:"女"}// 如果要修改數組內的某個索引對應的值(對象)的屬性,則可以生效// this.friends[0].name="sudada"// 如果使用官方推薦的7種方法(push末尾行追加,pop末尾行刪除,unshift首行追加,shift首行刪除,splice數組內某個元素替換,sort排序,reverse反轉數組)修改,Vue是生效的this.friends.unshift({name:"wss",age:18,sex:"女"})}}}) </script>14.4.3、總結Vue監視數據的原理
? 1、vue會監視data中所有層次的數據
? 2、如何監測對象中的數據?
? ? 通過setter實現監視,且要在new Vue時就傳入要監測的數據。
? ? ? 1.對象中后追加的屬性,Vue默認不做響應式處理
? ? ? 2.如需給后添加 的屬性做響應式,請使用如下API(2選1)
? ? ? ? Vue.set(target, propertyName, value)
? ? ? ? vm.$set(target, propertyName, value)
? 3、如何監測數組中的數據?
? ? 通過包裹數組更新元素的方式實現,本質就是做了兩件事
? ? ? 1.調用原生對應的方法對數組進行更新
? ? ? 2.重新解析模板,進而更新頁面
? 4、在Vue修改"數組"中的某個元素的辦法
? ? 1.使用:push末尾行追加,pop末尾行刪除,unshift首行追加,shift首行刪除,splice數組內某個元素替換,sort排序,reverse反轉數組
? ? 2.Vue.set 或者 vm.$set
? 5、特別注意:
? ? Vue.set 和 vm.$set 不能給vm或者vm的"根數據對象"(也就是data) 添加屬性。
? 6、代碼示例
<body> <div id="root"><h1>學生信息</h1><button @click="student.age++">點我年齡加一</button> <br><button @click="addsex">添加一個性別</button> <br><button @click="student.sex='未知'">修改性別</button> <br><button @click="addfriend">添加朋友</button> <br><button @click="updatefirstfriendname">修改第一個朋友的名字</button> <br><button @click="addhoppy">添加一個愛好</button> <br><button @click="changehoppy">修改第一個愛好,開車</button> <br><button @click="nosmoke">過濾掉抽煙的愛好</button> <br><h2>姓名:{{student.name}}</h2><h2>年齡:{{student.age}}</h2><h2 v-if="student.sex">性別:{{student.sex}}</h2><h2>愛好</h2><ul><li v-for="(h,index) in student.hoppy" :key="index">{{h}}</li><h3>朋友們</h3><li v-for="(f,index) in student.friends">{{f.name}}--{{f.age}}---{{f.sex}}</li></ul> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{student:{name:"sudada",age:18,hoppy:["抽煙","喝酒","燙頭"],friends:[{name:"yyy",age:18,sex:"女"},]}},methods:{addsex(){vm.$set(this.student,'sex','男')},addfriend(){this.student.friends.unshift({name:"szq",age:28,sex:"男"})},updatefirstfriendname(){this.student.friends[0].name="張三"},addhoppy(){this.student.hoppy.push("打游戲")},changehoppy(){// 方法1:hoppy.splice(0,1,'開車') 把數組hoppy的第0個索引刪掉,然后插入1個新的索引,值為"開車"。// this.student.hoppy.splice(0,1,'開車')// 方法2:把數組hoppy的第0個索引值改為'開車'Vue.set(this.student.hoppy,0,'開車')},nosmoke(){this.student.hoppy = this.student.hoppy.filter((h)=>{return h !== '抽煙'})}}}) </script>十五、收集form表單中的數據
15.1、例子
<body><div id="root"><!-- 表達提交時(阻止默認行為"跳轉頁面"),觸發的點擊事件"demo" --><form @submit.prevent="demo"><!-- v-model.trem:去除input框內首位輸入的"空格" -->賬號:<input type="text" v-model.trim="account"> <br>密碼:<input type="password" v-model="password"><br><!-- type="number":input框輸入的值,只能是整數類型 --><!-- v-model.number:Vue把收集到的值,轉換為整數類型 --><!-- type="number" 和 v-model.number,一般同時使用 -->年齡:<input type="number" v-model.number="age"><br>性別<br><!-- name="sex":選項框只能勾選一個 --><!-- value="male|female":因為使用了"v-model",而"v-model"需要綁定value,所以就單獨寫一個value -->男:<input type="radio" name="sex" v-model="sex" value="male">女:<input type="radio" name="sex" v-model="sex" value="female"><br>愛好<br><!-- value="chouyan|hejiu|tangtou":同樣因為使用了"v-model",而"v-model"需要綁定value,所以就單獨寫一個value --><!-- 當type="checkbox"時(多組的勾選框),v-model="hobby"中的"hobby"需要為數組類型 -->抽煙:<input type="checkbox" v-model="hobby" value="chouyan" >喝酒:<input type="checkbox" v-model="hobby" value="hejiu">燙頭:<input type="checkbox" v-model="hobby" value="tangtou"><br>所屬校區:<select v-model="city"><option value="">請選擇校區</option><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option><option value="wuhan">武漢</option></select><br>其他信息:<!-- v-model.lazy:等待input輸入完之后,鼠標點擊別處時,Vue再收集數據 --><textarea v-model.lazy="other"></textarea><br><!-- v-model="agree":這里只需要拿到一個"布爾值"即可(勾選是true,不勾選是false),不需要拿里面輸入的內容 --><input type="checkbox" v-model="agree"> 閱讀并接受用戶協議:<a href="http://www.baidu.com">《用戶協議》</a><br><button>提交</button></form></div> </body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el:"#root",data:{account:'',password:'',age:'',sex:'male',hobby:[],city:'shanghai',other:'',agree:false,},methods:{demo(){console.log(this._data)}}}) </script>15.2、收集form表單數據總結:
如果:input type="text/password/number" 則v-model收集的是value的值,用戶輸入的就是value的值。
如果:input type="radio" 則v-model收集的是value的值,且要給標簽配置value值。
如果:input type="checkbox"
? ? 1.沒有配置input的value屬性,那么收集的就是checked (勾選就是true 或 未勾選是false,是布爾值)
? ? 2.配置input的value屬性:
? ? ? ? 2.1.v-model的初始值是非數組類型,那么收集的就是checked (勾選就是true 或 未勾選是false,是布爾值)
? ? ? ? 2.2.v-model的初始值是數組類型,那么收集的就是value組成的數組(是一個數組)
v-model的三個修飾符
? ? 1.v-model.lazy:失去焦點后在收集數據(不是事實采集數據,是輸入完畢后,點擊下一行時,在采集)
? ? 2.v-model.number:輸入字符串轉為有效地數字
? ? 3.v-model.trim:輸入的字符串,首尾空格過濾(中間的空格不過濾)
十六、過濾器
16.1、過濾器的定義:對要顯示的數據進行特定格式化后在顯示(適用于一些簡單邏輯的處理)
16.2、過濾器語法:
? ? ? ? 1.注冊過濾器:Vue.filter(name,callback) 或者 new Vue(filters:{})
? ? ? ? 2.使用過濾器:{{xxx | 過濾器名}} 或 v-bind:屬性 = "xxx | 過濾器名"
16.3、過濾器使用備注:
? ? ? ? 1.過濾器也可以接收額外參數,多個過濾器也可以串聯
? ? ? ? 2.并沒有改變原本的數據,是產生新的對應的數據。
16.4、例子
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript" src="../js/vue.js"></script><script type="text/javascript" src="../js/dayjs.min.js"></script> </head><body> <div id="root"><h2>格式化后的時間</h2><!-- 計算屬性實現 --><h3>現在是{{fmtTime}}</h3><!-- methods實現 --><h3>現在是{{getfmtTime()}}</h3><!-- 過濾器實現(本質就是函數),其中timeFormater是(過濾器)函數,time作為函數的參數傳遞給timeFormater --><h3>現在是{{time | timeFormater}}</h3><!-- 過濾器傳參(默認第一個參數(value)是time,第二個參數(str)是'YYYY_MM_DD') --><h3>現在是{{time | timeFormater('YYYY_MM_DD')}}</h3><!-- 過濾器傳參(timeFormater默認第一個參數(value)是time,第二個參數(str)是'YYYY_MM_DD',然后把timeFormater函數執行后的返回值,作為參數傳遞給mySlice) --><!-- "time"傳遞"timeFormater","timeFormater"傳遞給"mySlice",向下傳遞的過程 --><h3>現在是{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3> </div> </body><script type="text/javascript">Vue.config.productionTip = false// 全局過濾器,這里的mySlice可以參考下面的局部過濾器寫法對比即可。// Vue.filter('mySlice',function (value){// return value.slice(0,4)// })new Vue({el:"#root",data:{time:1621561377603,},computed:{fmtTime(){return dayjs(this.time).format("YYYY年-MM月-DD日 HH:mm:ss")}},methods:{getfmtTime(){return dayjs(this.time).format("YYYY年-MM月-DD日 HH:mm:ss")}},// 局部過濾器,關鍵字 "filters"filters:{// 函數接受的參數value,其實就是time。// 參數str就是傳遞過來的'YYYY_MM_DD'// str='YYYY年-MM月-DD日 HH:mm:ss',參數str的默認值timeFormater(value,str='YYYY年-MM月-DD日 HH:mm:ss'){return dayjs(value).format(str)},mySlice(value){console.log(value)// value = 2021_05_21,取前4位return value.slice(0,4)},}}) </script>十七、內置指令
17.1、v-test 指令使用
v-bind:單向綁定解析表達式,可簡寫為 :xxx
? ? 例子:age="29"拿到的就是字符串類型"29",:age="29"拿到的就是經過js解析后的值,是一個整數類型29
v-model:雙向數據綁定
v-for:便利數組/對象/字符串
v-on:綁定事件監聽,可以簡寫為 @
v-if:條件渲染(動態控制節點是否存在)
v-else:條件渲染(動態控制節點是否存在)
v-show:條件渲染(動態控制節點是否展示)
v-test:
??1.作用:向其所在的節點中"渲染"文本內容
??2.與插值語法的區別,v-text會替換掉標簽中的內容,{{xx}}插值語法則不會。
? 3.v-test例子
17.2、v-html 指令使用
? ? 1.作用:向指定節點中渲染包含 "html結構" 的內容
? ? 2.與插值語法的區別
? ? ? ? 1.v-html會替換掉標簽中所有的內容,{{xx}}插值語法則不會
? ? ? ? 2.v-html可以識別html結構。
? ? 3.嚴重注意:v-html有安全性問題!
? ? ? ? 1.在網站上動態渲染任意html是非常危險的,容易導致XSS攻擊、
? ? ? ? 2.一定要在可信任的內容上使用v-html,永遠不要再用戶提交的內容上。
17.3、v-cloak?指令使用
1.本質是一個特殊屬性,Vue實例創建完畢并接管容器后,會刪掉v-cloak屬性
2.使用css配合v-cloak 可以解決網速慢時,頁面展示出{{xxx}}的問題。
17.4、v-once?指令使用
1.v-once所在節點在初次動態渲染之后,就為靜態內容了
2.之后數據的改變不會引起v-once所在結構的更新,可以用于優化性能。
17.5、v-pre?指令使用
1.加上v-pre指令之后,該行就變成"所見即所得",也就是vue不解析該行代碼了。
2.跳過其所在節點的編譯過程
3.可利用它跳過:沒有使用指令語法,沒有使用插值語法的節點,會加快編譯。
十八、自定義指令
18.1、函數式(例子:定義個v-big指令,和v-text指令類似,但會把綁定的數值放大10倍)
<body> <div id="root"><h1>hello, {{name}}</h1><h2>當前的值是:<span v-text="n"></span></h2><h2>放大10倍后的n值是 <span v-big="n"></span> </h2><button @click="n++">點我N+1</button> </div> </body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el:"#root",data:{name:"sudada",n:1},// 定義一個自定義指令(局部指令),這個指令本質就是一個函數,但是不能寫返回值,也就是不寫returndirectives:{// big函數何時會被調用?// 1.指令與元素成功綁定時。// 2.指令所在的模板被重新解析時。big(element,binding){console.log(element) // "element"是真實的DOM元素(div里面v-big是是放在span里面的,那么這里的DOM就是span)console.log(binding) // "binding"是一個對象,里面有個value,這個value就是v-big="n"里面"n"的值// element.innerText:原生dom結構,元素內的文本內容。element.innerText = binding.value * 10}}}) </script>18.2、對象式(例子:定義個v-fbind指令,和v-bind指令類似,但可以讓其所綁定的input元素默認獲取焦點)
<body> <div id="root"><h1>hello, {{name}}</h1><h2>當前的值是:<span v-text="n"></span></h2><h2>放大10倍后的n值是 <span v-big="n"></span> </h2><button @click="n++">點我N+1</button><br><input type="text" v-fbind:value="n"> </div> </body><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el:"#root",data:{name:"sudada",n:1},// 局部指令directives:{// big函數式// 1.指令與元素成功綁定時。// 2.指令所在的模板被重新解析時。big(element,binding){element.innerText = binding.value * 10},// fbind對象式// 和上面big函數式的區別:"big函數式"只執行了"bind函數"和"update函數",沒有執行"inserted函數"。fbind:{// 指令與元素成功綁定時,執行bind函數bind(element,binding){console.log("bind")element.value=binding.value},// 指令所在元素被插入頁面時,執行inserted函數inserted(element,binding){console.log("inserted")element.focus()},// 指令所在的模板被重新解析時,執行update函數update(element,binding){console.log("update")element.value=binding.value},}}}) </script>18.3、自定義指令 總結
18.3.1、定義語法
? ? 1.1、局部指令
? ? ? ? new Vue({
? ? ? ? ? ? directives:{指令名:配置對象}
? ? ? ? }) 或者
? ? ? ? new Vue({
? ? ? ? ? ? directives(){指令名:回調函數}
? ? ? ? })
? ? 1.2、全局指令
? ? ? ? Vue.directive(指令名:配置對象) 或者 Vue.directive(指令名:回調函數)
18.3.2、配置對象中常用的3個回調:
? ? 1.bind:指令與元素成功綁定時調用。
? ? 2.inserted:指令所在元素被插入頁面時調用。
? ? 3.update:指令所在模版結構被重新解析時調用。
18.3.3、
? ? 1.指令定時不加"v-",但是使用時要加"v-"。
? ? 2.指令名如果是多個單詞,要是有kebab-case命名方式,不能使用camelCase(駝峰體)。
十九、Vue生命周期函數
19.1、什么是周期回調函數
? ? 1.又名:生命周期回調函數,生命周期函數,生命周期鉤子
? ? 2.是什么:vue在關鍵時刻幫我們調用的一些特殊名稱的函數
? ? 3.生命周期函數的名字不可更改,但函數的具體內容是程序員根據需求編寫的
? ? 4.生命周期函數中的this指向的是 vm 或 vue組件實例對象。
19.2、總結生命周期
19.2.1、常用的生命周期鉤子:
? ? 1.mounted:常用來發送ajax請求,啟動定時器,綁定自定義事件,訂閱消息等(初始化操作)
? ? 2.beforeDestroy:常用來清除定時器,解綁自定義事件,取消訂閱消息等(收尾工作)
19.2.2、關于銷毀vue實例
? ? 1.銷毀后借助vue開發工具看不到任何信息。
? ? 2.銷毀后自定義事件會失效,但原生DOM事件依然有效。
19.3、生命周期圖示
二十、組件的使用
20.1、什么是組件?
????????組件是實現應用中"局部"功能"代碼(html,css,js)"和"資源(各種文件)"的"集合"。
組件式編程的方式,如下圖:
什么是模塊?
????????模塊一般就是一個js文件
為什么使用組件?
????????復用編碼,簡化項目編碼,提高運行效率。
20.2、非單文件組件(一個文件中有多個組件)缺點:樣式CSS不能跟著組件走
20.2.1、組件的基本使用方法(三大步驟)
1、定義組件
? ? 使用Vue.extend(options)創建,其中options和new Vue(options)時傳入的那個options幾乎一樣,但區別如下:
? ? 1.el不寫,原因:最終所有的組件都要經過一個vm管理,由vm中的el決定服務哪個容器
? ? 2.data必須寫成函數,原因:避免組件被復用時,數據存在引用關系
? ? 備注:使用template可以配置組件結構
2、注冊組件(分局部注冊和全局注冊)
? ? 1.局部注冊:在vm里面傳入components選項
? ? 2.全局注冊:使用Vue.component("組件名",組件值)
3、使用組件(寫"組件"標簽即可實現組件的使用與復用)
? ? <組件名></組件名>
4、案例
<body> <div id="root"><h2>{{msg}}</h2><!-- 第三步:使用組件(直接寫"組件"標簽即可實現組件的使用與復用) --><school></school><school></school><hr><student></student><student></student><hr><!-- 第3步:使用全局組件(直接寫"組件"標簽即可實現組件的使用與復用) --><hello></hello> </div> </body><script type="text/javascript">Vue.config.productionTip = false// 第一步:創建school組件:Vue.extend// 組件定義式不需要寫"el"配置項// data必須要寫函數式,這樣每次拿到的值都是一樣的,如果寫成對象式的話,會在內存里面有引用關系,會修改對象內的值。const school = Vue.extend({// 非單文件組件使用"template"這種方式template:`<div><h2>學校名稱:{{schoolname}}</h2><h2>學校地址:{{address}}</h2></div>`,data(){return {schoolname:"學校",address:"上海",}}})// 第一步:創建student組件const student = Vue.extend({// 非單文件組件使用"template"這種方式template:`<div><h2>學生地址:{{name}}</h2><h2>學生名稱:{{age}}</h2></div>`,data(){return {name:"王大陸",age:18}}})// 第1步:創建hello組件(這個組件用來注冊全局組件)const hello = Vue.extend({// 非單文件組件使用"template"這種方式template:`<div><h2>你好啊~{{name}}</h2></div>`,data(){return {name:"牛牛牛",}}})// 第2步:注冊全局組件Vue.component('hello',hello)const vm = new Vue({el:"#root",data:{msg:"hello"},// 第二步:注冊組件(局部注冊)// 使用關鍵字:components,對象格式,里面的"key"就是使用時的"組件名"components:{school:school,student:student}}) </script>20.2.2、組件的注意點
? ? 1.關于組件名稱:
? ? 一個單詞組成的"組件名":
? ? ? ? 寫法1:school(首字母小寫)
? ? ? ? 寫法2:School(首字母大寫)
? ? 多個單詞組成的"組件名":
? ? ? ? 寫法1:'my-school'(必須要有引號)
? ? ? ? 寫法2:MySchool (需要腳手架支持,否則報錯)
? ? 備注:
? ? ? ? 組件名不能和HTML已有的元素名稱重復,比如:h2,H2都不行
? ? ? ? 可以使用name配置項,指定組件在瀏覽器Vue開發者工具中呈現的名稱。
? ? 2.關于組件標簽
? ? ? ? 寫法1:<school></school> ?常用
? ? ? ? 寫法2:<school/> ?不用腳手架時,<school/>會導致后續組件不能渲染。
? ? 3.組件的簡寫方式:
? ? ? ? const school = Vue.extend({options}) 可簡寫為:const school = {options}
4.案例(包含上述1,2,3)
<body> <div id="root"><h1>hello,{{name}}</h1><school></school> <!-- 寫法1,推薦 --><!-- <school/> 寫法2:單閉合 --> </div> </body><script type="text/javascript">Vue.config.productionTip = false// 組件定義簡寫:不需要 Vue.extend()const school = {// name:定義組件時,給組件起的別名(這個別名也就是瀏覽器Vue開發者工具拿到的組件名)// 具體在代碼里面使用時還是要寫'components'注冊的組件名name:'sudada',template:`<div><h2>學校名稱:{{schoolName}}</h2><h2>學校地址:{{address}}</h2></div>`,data(){return {"schoolName": "上海大學","address":"shanghai",}}}const vm = new Vue({el:"#root",data:{name:"szq",addr:"shanghai",},components:{school:school}}) </script>5.還有個特殊的點(可以使用name配置項,指定組件在瀏覽器Vue開發者工具中呈現的名稱。)
在定義組件時,定義一個name屬性,那么這個屬性就能被開發者工具識別到。
20.2.3、組建的嵌套
簡單理解組件的嵌套:外面的就是父組件,里面的就是子組件。
組件嵌套的例子:
<body> <div id="root"><app></app> </div> </body><script type="text/javascript">Vue.config.productionTip = false// 組件定義:student組件(子組件)const student = Vue.extend({template:`<div><h2>學生名稱:{{studentName}}</h2><h2>學生年齡:{{age}}</h2></div>`,data(){return {"studentName": "蘇兆強","age":18,}}})// 組件定義:school組件(父組件)const school = Vue.extend({template:`<div><h2>學校名稱:{{schoolName}}</h2><h2>學校地址:{{address}}</h2><student></student></div>`,data(){return {"schoolName": "上海大學","address":"shanghai",}},// school組件內,注冊子組件student(局部注冊)components:{student:student,}})// 組件定義:hello組件const hello = Vue.extend({template:`<div><h2>hello:{{name}}</h2></div>`,data(){return {"name": "sudada",}}})// 組件定義:app組件 (主組件)const app = Vue.extend({template:`<div><hello></hello><school></school></div>`,// app組件內,注冊子組件school和hello(局部注冊)components:{school:school,hello:hello,}})// 注冊組件(局部)const vm = new Vue({el:"#root",components:{app:app,}}) </script>20.2.4、VueComponent分析
VueComponent說明:
? ? 前言:vc 是源碼vue.extend里面的VueComponent函數執行后返回的對象:
? ? ? ? Vue.extend = function (extendOptions) {
? ? ? ? ? var Sub = function VueComponent (options) {
? ? ? ? ? this._init(options);
? ? ? ? ? };
? ? ? ? ? return Sub
? ? 1.school 組件本質是一個名為VueComponent"構造函數",且不是程序員定義的,是Vue.extend生成的。
? ? 2.我們只需要寫<school></school>,vue解析時會幫我們創建school組件的實例對象,即Vue幫我們執行的:new VueComponent(options)。
? ? 3.特別注意:每次調用vue.extend,返回的都是一個全新的VueComponent。
? ? 4.關于this指向:
? ? ? ? 1.在"組件"配置中:
? ? ? ? ? ? data函數、methods函數、watch函數、computed函數 他們的this均是 【VueComponent實例對象,簡稱vc,也就是組件實例對象】
? ? ? ? 2.在New Vue({options}) 配置中:
? ? ? ? ? ? data函數、methods函數、watch函數、computed函數 他們的this均是 【Vue實例對象,簡稱vm】
? ? ? ? 3.vm下的$children可以看到對應的vc,也就可以理解為vm管理vc。如果vc內部還有子組件的話,那就去vc下的$children可以看到對應的子vc。
? ? 5.vm 和 vc 的區別
? ? ? ? vm有el屬性,vc沒有,同時vc也沒法定義el。其他的屬性都一樣。
? ? 6.children 例子:vm里面注冊了school組件(school組件里面注冊了student組件)
<body> <div id="root"><school></school> </div> </body><script type="text/javascript">Vue.config.productionTip = falseconst student = Vue.extend({template:`<div><h2>學生名稱:{{studentName}}</h2><h2>學生年齡:{{age}}</h2></div>`,data(){return {"studentName": "王大陸","age":18,}}})const school = Vue.extend({template:`<div><h2>學校名稱:{{schoolName}}</h2><h2>學校地址:{{address}}</h2><student></student></div>`,data(){return {"schoolName": "上海大學","address":"shanghai",}},components:{student:student}})const vm = new Vue({el:"#root",data:{name:"szq"},components:{school:school}}) </script>? children 例子展示:
20.2.5、一個重要的內置關系(VueComponent.prototype.__proto__ = Vue.prototype)
為什么要有這個關系:讓(組件實例對象vc)可以訪問到"Vue原型"上的屬性和方法。
?舉例說明:
<body> <div id="root"><school></school> </div> </body><script type="text/javascript">Vue.config.productionTip = false// // 定義一個構造函數// function demo(){// this.a=10// this.b=20// }// // 創建一個d實例對象// const d = new demo()//// console.log(demo.prototype) //顯示原型屬性(函數才有這個屬性)// console.log(d.__proto__) //隱式原型屬性(對象才有這個屬性)// 定義Vue的原型屬性,在里面新增一個:x=99Vue.prototype.x = 99// 組件定義 (組件實例對象vc)const school = Vue.extend({template:`<div><h2>學校名稱:{{schoolName}}</h2><h2>學校地址:{{address}}</h2><button @click="showX">點我查看x</button></div>`,data(){return {"schoolName": "上海大學","address":"shanghai",}},methods:{showX(){// 在這里通過(組件實例對象vc)獲取Vue的原型屬性: x=99// 這里的this就是(組件實例對象vc)console.log(this.x)}}})const vm = new Vue({el:"#root",data:{name:"sudada",addr:"shanghai",},components:{school:school},}) </script>20.3、單文件組件.vue(一個文件中只有一個組件)
"非單文件組件" 格式
<script>// 非單文件組件寫法const school = Vue.extend({data(){return {"schoolName": "上海大學","address":"shanghai",}},methods:{showName(){alert(this.schoolName)}}}) </script>"單文件組件" 默認暴露的簡寫方式
<!-- 組件的結構(HTML) --> <template> <div class="demo"><h2>學校名稱:{{name}}</h2><h2>學校地址:{{address}}</h2><button @click="showName">點我顯示學校名稱</button> </div> </template><!-- 組件交互的代碼(JS) --> <script>// 單文件組件的簡寫方式:暴露方式3("默認暴露"),簡寫方式export default {name: "School", // name配置項,指定組件在瀏覽器Vue開發者工具中呈現的名稱data(){return {"name": "上海大學","address":"shanghai",}},methods:{showName(){alert(this.schoolName)}}} </script><!-- 組件的樣式(CSS) --> <style>.demo{background-color: orange;} </style>"單文件組件"的其他暴露方式
<script>// "分別暴露",主要是給import引用使用 (暴露方式1) import {xxx} from './xxx'export const school = Vue.extend({data(){return {"schoolName": "上海大學","address":"shanghai",}},methods:{showName(){alert(this.schoolName)}}}) </script><script>const school = Vue.extend({data(){return {"schoolName": "上海大學","address":"shanghai",}},methods:{showName(){alert(this.schoolName)}}})export {school} // "統一暴露"(代碼就是寫在底部),主要是給import引用使用(暴露方式2)import {xxx} from './xxx' </script><script>const school = Vue.extend({data(){return {"schoolName": "上海大學","address":"shanghai",}},methods:{showName(){alert(this.schoolName)}}})export default school // "默認暴露"(代碼就是寫在底部),主要是給import引用使用(暴露方式3,推薦) import xxx from './xxx' </script>X、函數調用表達式
<div id="root">addr.toUpperCase() 字符串大寫addr.toLowerCase() 字符串小寫 </div># if 判斷 if(e.target.value !== 13) return# 定時器,延時1000毫秒后執行 setTimeout(()=>{console.log("xxx") },1000)# 三元表達式(如果a=3。返回100,否則返回200) a === 3 ? 100 : 200# 在數組的開頭添加一個值 persons=[] const p = {id:'004',name:'laoliu',age:49} persons.unshift(p) this.persons.push(p) #在數組的末尾添加一個值#filter方法(過濾數組內某個值) persons: [{id: "001", name: "馬冬梅", age: 18, sex: "女"},{id: "002", name: "周冬雨", age: 28, sex: "女"},{id: "003", name: "周杰倫", age: 38, sex: "男"},{id: "004", name: "溫兆倫", age: 48, sex: "男"}, ], this.persons.filter((p)=>{ // indexOf(value) == -1 說明沒匹配到,indexOf(value)等于其他"0,1,2,xxx"表示匹配數據的索引值(也就是匹配到了)。 return p.name.indexOf(value) !== -1# sort排序 let arr = [1,3,6,2,5,4] arr.sort((a,b)=>{return a-b }) console.log(arr) // return a-b:升序 [1, 2, 3, 4, 5, 6] // return a-b:降序 [6, 5, 4, 3, 2, 1]總結
- 上一篇: Mac电脑上最好用的3个azw/azw3
- 下一篇: 废旧Android手机搭建个人服务器:k