Vue2学习笔记
推薦大家安裝的 VScode 中的 Vue 插件
Vue 3 Snippets Vue 3 Snippets - Visual Studio Marketplace
Vetur Vetur - Visual Studio Marketplace
什么是 vue
構建用戶界面
-
用 vue 往 html 頁面中填充數據,非常的方便
框架
-
框架是一套現成的解決方案,程序員只能遵守框架的規范,去編寫自己的業務功能!
-
要學習 vue,就是在學習 vue 框架中規定的用法!
-
vue 的指令、組件(是對 UI 結構的復用)、路由、Vuex、vue 組件庫
-
只有把上面老師羅列的內容掌握以后,才有開發 vue 項目的能力!
vue 的兩個特性
數據驅動視圖:
-
數據的變化會驅動視圖自動更新
-
好處:程序員只管把數據維護好,那么頁面結構會被 vue 自動渲染出來!
雙向數據綁定:
在網頁中,form 表單負責采集數據,Ajax 負責提交數據。
-
js 數據的變化,會被自動渲染到頁面上
-
頁面上表單采集的數據發生變化的時候,會被 vue 自動獲取到,并更新到 js 數據中
注意:數據驅動視圖和雙向數據綁定的底層原理是 MVVM(Mode 數據源、View 視圖、ViewModel 就是 vue 的實例)
vue 指令
1. 內容渲染指令 (用來輔助開發者渲染DOM元素的文本類容)
v-text 指令的缺點:會覆蓋元素內部原有的內容!
{{ }} 插值表達式:在實際開發中用的最多,只是內容的占位符,不會覆蓋原有的內容!
v-html 指令的作用:可以把帶有標簽的字符串,渲染成真正的 HTML 內容!
2. 屬性綁定指令
注意:插值表達式只能用在元素的內容節點中,不能用在元素的屬性節點中!
-
在 vue 中,可以使用 v-bind: 指令,為元素的屬性動態綁定值;
-
簡寫是英文的 :
-
在使用 v-bind 屬性綁定期間,如果綁定內容需要進行動態拼接,則字符串的外面應該包裹單引號,例如:
<div :title="'box' + index">這是一個 div</div>
3. 事件綁定
v-on: 簡寫是 @
語法格式為:
<button @click="add"></button> ? methods: {add() {// 如果在方法中要修改 data 中的數據,可以通過 this 訪問到this.count += 1} }$event 的應用場景:如果默認的事件對象 e 被覆蓋了,則可以手動傳遞一個 $event。例如:
<button @click="add(3, $event)"></button> ? methods: {add(n, e) {// 如果在方法中要修改 data 中的數據,可以通過 this 訪問到this.count += 1} }事件修飾符:
-
.prevent 阻止事件默認行為
<a @click.prevent="xxx">鏈接</a> -
.stop 阻止冒泡
<button @click.stop="xxx">按鈕</button>
4. v-model 指令(雙向綁定指令)
input 輸入框
-
type="radio"
-
type="checkbox"
-
type="xxxx"
textarea
select
v-model指令的修飾符
-
.number 自動將用戶的輸入值轉換為數值類型
<input v-model.number="age" /> -
.trim 自動過濾用戶輸入的首尾空白字符
<input v-model.trim="msg" /> -
.lazy 在“ change ” 時而非“ input ” 時更新
<input v-model.lazy="msg" />
5. 條件渲染指令
v-show 的原理是:動態為元素添加或移除 display: none 樣式,來實現元素的顯示和隱藏
-
如果要頻繁的切換元素的顯示狀態,用 v-show 性能會更好
v-if 的原理是:每次動態創建或移除元素,實現元素的顯示和隱藏
-
如果剛進入頁面的時候,某些元素默認不需要被展示,而且后期這個元素很可能也不需要被展示出來,此時 v-if 性能更好
在實際開發中,絕大多數情況,不用考慮性能問題,直接使用 v-if 就好了!!!
v-if 指令在使用的時候,有兩種方式:
直接給定一個布爾值 true 或 false
<p v-if="true">被 v-if 控制的元素</p>給 v-if 提供一個判斷條件,根據判斷的結果是 true 或 false,來控制元素的顯示和隱藏
<p v-if="type === 'A'">良好</p>6.列表渲染指令
v-for指令需要使用 item in items 的形式的特殊語法
items是待循環的數組 item是被循環的每一項
data:{list:[{id:1,name:'zs'},{id:2,name:'ls'} ] } ? <ul><li v-for="item in list">姓名是:{{item.name}}</li> </ul>v-for指令還支持一個可選的第二個參數,即當前項的索引。 語法格式為(item,index)in items.
3.官方建議:只要用到了v-for指令,那么一定要綁定一個:key屬性,而且盡量把Id作為key的值
4.官方對于key的類型是有要求的:字符串或數字類型。 key值不能重復,必須具有唯一性
過濾器
過濾器的注意點
要定義到 filters 節點下,本質是一個函數
在過濾器函數中,一定要有 return 值
在過濾器的形參中,可以獲取到“管道符”(|)前面待處理的那個值
如果全局過濾器和私有過濾器名字一致,此時按照“就近原則”,調用的是”私有過濾器“
watch 偵聽器
偵聽器的格式
方法格式的偵聽器
-
缺點1:無法在剛進入頁面的時候,自動觸發!!!
-
缺點2:如果偵聽的是一個對象,如果對象中的屬性發生了變化,不會觸發偵聽器!!!
對象格式的偵聽器
-
好處1:可以通過 immediate 選項,讓偵聽器自動觸發!!!
-
好處2:可以通過 deep 選項,讓偵聽器深度監聽對象中每個屬性的變化!!!
watch偵聽器允許開發者監視數據的變化,從而針對數據的變化做特定的操作
<div id="app"><input type="text" v-model="username"></div><script>const vm = new Vue({el: '#app',data: {username: 'admin'},// 所有的偵聽器,都應該被定義到 watch 節點下watch: {// 偵聽器本質上是一個函數,要監視哪個數據的變化,就把數據名作為方法名即可// 新值在前,舊值在后username(newVal,oldVal) {console.log(newVal,oldVal)}}})</script>計算屬性
定義到computed中
特點:
定義的時候,要被定義為“方法”
在使用計算屬性的時候,當普通的屬性使用即可
好處:
實現了代碼的復用
只要計算屬性中依賴的數據源變化了,則計算屬性會自動重新求值!
axios
axios 是一個專注于網絡請求的庫!
axios 的基本使用
發起 GET 請求:
axios({// 請求方式method: 'GET',// 請求的地址url: 'http://www.liulongbin.top:3006/api/getbooks',// URL 中的查詢參數params: {id: 1} }).then(function (result) {console.log(result) })發起 POST 請求:
document.querySelector('#btnPost').addEventListener('click', async function () {// 如果調用某個方法的返回值是 Promise 實例,則前面可以添加 await!// await 只能用在被 async “修飾”的方法中const { data: res } = await axios({method: 'POST', url: 'http://www.liulongbin.top:3006/api/post',data: {name: 'zs',age: 20}}) ?console.log(res) })vue-cli 的使用
在終端下運行如下的命令,創建指定名稱的項目:
vue cerate 項目的名稱vue 項目中 src 目錄的構成:
? assets 文件夾:存放項目中用到的靜態資源文件,例如:css 樣式表、圖片資源 components 文件夾:程序員封裝的、可復用的組件,都要放到 components 目錄下 main.js 是項目的入口文件。整個項目的運行,要先執行 main.js App.vue 是項目的根組件。vue組件
1.介紹與使用
-
組件在被封裝好之后,彼此之間是相互獨立的,不存在父子關系。
-
在使用組件的時候,根據彼此的嵌套關系,形成父子關系,兄弟關系。
-
使用組件的三個步驟
-
使用import語法導入需要的組件
import left from '@/components/left.vue' -
使用components節點注冊組件 (通過components注冊的是私有組件)
export default{compoments:{left} } -
以標簽形式使用剛才注冊的組件
<div class="box"><left></left> </div>
2.注冊全局組件
在vue項目的 main.js 入口文件中,通過 vue.components() 方法,可以注冊全局組件。如下
//導入需要被注冊的組件 import Count from '@/components/Count.vue'//參數1:字符串格式,表示組件的“注冊名稱” //參數2:需要被全局注冊的那個組件Vue.components('MyCount','Count')3.組件中的props
-
props是組件的自定義屬性,在封裝通用組件的時候,合理地使用props可以極大地提高組件的復用性!
export default{//組件的自定義屬性props:['自定義屬性A','自定義屬性B','其他自定義屬性...'],//組件的私有數據data(){return{}} } -
props中的數據,可以直接在模板結構中使用
-
props是只讀的,不能直接修改props的值,想要修改props的值,可以吧props的值轉存到data中(data中的數據都是可讀可寫的!)
export default{//組件的自定義屬性props:['自定義屬性A','自定義屬性B','其他自定義屬性...'],//組件的私有數據data(){return{count:this.init}} } -
在聲明自定義屬性時,可以通過default來定義屬性的默認值。例如:
export default{//組件的自定義屬性props:{init:{//用default 屬性定義屬性的默認值default:0}} }
4.props的type值類型
-
在聲明自定義屬性時,可以通過type來定義屬性的值類型
export default{//組件的自定義屬性props:{init:{//用default 屬性定義屬性的默認值default:0,//如果傳遞過來的值不符合此類型,則會在終端報錯type:Number}} }
5.required必填項
export default{//組件的自定義屬性props:{init:{//用default 屬性定義屬性的默認值default:0,//如果傳遞過來的值不符合此類型,則會在終端報錯type:Number,//必填校驗項,如果不傳init 則終端報錯 required:true}} }6.組件之間的樣式沖突問題
默認情況下,寫在.vue組件中的樣式會全局生效,因此會造成多個組件之間的樣式沖突問題.
根本原因:
單頁面應用程序中,所有組件的DOM結構,都是基于唯一的index.html頁面進行呈現的
每個組件中的樣式,都會影響整個index.html頁面中的DOM元素
組件的生命周期
1.生命周期&生命周期函數
-
生命周期(Life Cycle)是指一個組件從創建->運行->銷毀的整個階段,強調的是一個時間段。
-
生命周期函數:是由Vue框架提供的內置韓式,會伴隨著組件的生命周期,自動按次序執行。
-
?
?
- <template><div class="test-container"><h3 id="myh3">Test.vue 組件 --- {{ books.length }} 本圖書</h3><p id="pppp">message 的值是:{{ message }}</p><button @click="message += '~'">修改 message 的值</button></div> </template><script> export default {props: ["info"],data() {return {message: "hello vue.js",// 定義 books 數組,存儲的是所有圖書的列表數據。默認為空數組!books: [],};},watch: {message(newVal) {console.log("監視到了 message 的變化:" + newVal);},},methods: {show() {console.log("調用了 Test 組件的 show 方法!");},// 使用 Ajax 請求圖書列表的數據initBookList() {const xhr = new XMLHttpRequest();xhr.addEventListener("load", () => {const result = JSON.parse(xhr.responseText);console.log(result);this.books = result.data;});xhr.open("GET", "http://www.liulongbin.top:3006/api/getbooks");xhr.send();},},// 創建階段的第1個生命周期函數beforeCreate() {// console.log(this.info)// console.log(this.message)// this.show()},created() {// created 生命周期函數,非常常用。// 經常在它里面,調用 methods 中的方法,請求服務器的數據。// 并且,把請求到的數據,轉存到 data 中,供 template 模板渲染的時候使用!this.initBookList();},beforeMount() {// console.log('beforeMount')// const dom = document.querySelector('#myh3')// console.log(dom)},// 如果要操作當前組件的 DOM,最早,只能在 mounted 階段執行mounted() {// console.log(this.$el)// const dom = document.querySelector('#myh3')// console.log(dom)},beforeUpdate() {// console.log('beforeUpdate')// console.log(this.message)// const dom = document.querySelector('#pppp')// console.log(dom.innerHTML)},// 當數據變化之后,為了能夠操作到最新的 DOM 結構,必須把代碼寫到 updated 生命周期函數中updated() {// console.log('updated')// console.log(this.message)// const dom = document.querySelector('#pppp')// console.log(dom.innerHTML)},beforeDestroy() {console.log("beforeDestroy");this.message = "aaa";console.log(this.message);},destroyed() {console.log("destroyed");// this.message = 'aaa'}, }; </script><style lang="less" scoped> .test-container {background-color: pink;height: 200px; } </style>
2.組件之間的數據共享
-
組件之間的關系(常見關系)
-
父子關系
-
兄弟關系
-
組件之間的數據共享
1.父組件向子組件共享數據需要使用自定義屬性。
2.子組件向父組件共享數據需要使用自定義事件。
-
兄弟組件之間的數據共享
在vue.2x中,兄弟組件之間數據共享的方案是EventBus
EventBus 的使用步驟
-
創建eventBus.js模塊,并向外共享一個Vue的實力對象
-
在數據發送方,調用 bus.$emit 方法觸發自定義事件
-
在數據接收方,調用 bus.$on 方法注冊一個自定義事件
?
ref引用
1.ref引用DOM
ref用來輔助開發者在不依賴jQuery的情況下,獲取DOM元素或組件的引用
<p ref="myp"></p>export default{methods:{this.$refs.myp.style.color = 'red'} }2.ref引用組件實例
可以用this.$refs.引用的名稱 來引用組件的實例
3.this.$nextTick(cb)方法
組件的$nextTick(cb) 方法,會把cb回調推遲到下一個DOM更新周期之后執行。
通俗的理解是:等組件的DOM更新完成之后,在執行cb回調函數。從而能保證cb 回調函數可以操作到最新的DOM元素。
動態組件
1.實現動態組件渲染
vue提供了一個內置的<component>組件,專門用來渲染實現動態組件的渲染
<template><div class="app-container"><h1>App 根組件</h1><hr /><button @click="comName = 'Left'">left</button><button @click="comName = 'Right'">right</button><div class="box"><!-- 渲染 Left 組件和 Right 組件 --><component :is="comName"></component></div></div> </template><script> import Left from "@/components/Left.vue"; import Right from "@/components/Right.vue"; export default {data() {return {comName: "",};},components: {Left,Right,}, }; </script>2.使用keep-alive 保持狀態
keep-alive 可以把內部的組件進行緩存,而不是銷毀組件
<keep-alive><component :is="comName"></component> </keep-alive>3. keep-alive 對應的生命周期函數
當組件被緩存時,會自動觸發組件的deactivated 生命周期函數
當組件被激活時,對自動觸發組件的activated 生命周期函數
4. keep-alive 的include屬性
<keep-alive include="Left,Right"> //指定哪些組件需要被緩存 <component :is="comName"></component> </keep-alive>插槽
1.什么是插槽
插槽(slot)是vue為組件的封裝者提供的能力。允許開發者在封裝組件時,把不確定的、希望用戶指定的部分定義為插槽。
?
vue官方規定:每一個 slot 插槽,都要有一個 name 名稱
如果省略了 slot 的 name 屬性,則有一個默認名稱叫做 default
2.v-slot指令
1. 如果要把內容填充到指定名稱的插槽中,需要使用 v-slot:這個指令 2. v-slot:后面要跟上插槽的名字 3. v-slot:指令不能用在元素身上,必須用在template標簽上 4. template這個標簽,它是一個虛擬標簽,只起到包裹性的作用 5. v-slot的簡寫是#3.后備內容
封裝組件時,可以為預留的<slot>插槽提供后備內容。如果組件的使用者沒有為插槽提供任何內容,則后備內容會生效。
4.作用域插槽
在封裝組件時,為預留的<slot>提供屬性對應的值,這種用法,叫做 “ 作用域插槽 ”。
<Left><template #con="obj"><h3>pppppp</h3><p>{{ obj.msg }}</p></template></Left><slot name="con" msg="hello"> </slot>自定義指令
1.vue中的自定義指令分為兩類
-
私有自定義指令
-
全局自定義指令
2.私有自定義指令
在每個vue組件中,可以在directives節點下聲明私有自定義指令。
//私有指令節點directives: {color: {bind(el) {el.style.color = "red";// console.log(111);},},}3.鉤子函數
指令定義函數提供了幾個鉤子函數(可選):
-
bind: 只調用一次,指令第一次綁定到元素時調用,用這個鉤子函數可以定義一個在綁定時執行一次的初始化動作。
-
inserted: 被綁定元素插入父節點時調用(父節點存在即可調用,不必存在于 document 中)。
-
update: 被綁定元素所在的模板更新時調用,而不論綁定值是否變化。通過比較更新前后的綁定值,可以忽略不必要的模板更新(詳細的鉤子函數參數見下)。
-
componentUpdated: 被綁定元素所在模板完成一次更新周期時調用。
-
unbind: 只調用一次, 指令與元素解綁時調用。
接下來我們來看一下鉤子函數的參數 (包括 el,binding,vnode,oldVnode) 。
鉤子函數被賦予了以下參數:
-
el: 指令所綁定的元素,可以用來直接操作 DOM 。
-
binding
: 一個對象,包含以下屬性:
-
name: 指令名,不包括 v- 前綴。
-
value: 指令的綁定值, 例如: v-my-directive="1 + 1", value 的值是 2。
-
oldValue: 指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。無論值是否改變都可用。
-
expression: 綁定值的字符串形式。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"。
-
arg: 傳給指令的參數。例如 v-my-directive:foo, arg 的值是 "foo"。
-
modifiers: 一個包含修飾符的對象。 例如: v-my-directive.foo.bar, 修飾符對象 modifiers 的值是 { foo: true, bar: true }。
-
-
vnode: Vue 編譯生成的虛擬節點,查閱 VNode API 了解更多詳情。
-
oldVnode: 上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。
除了 el 之外,其它參數都應該是只讀的,盡量不要修改他們。如果需要在鉤子之間共享數據,建議通過元素的 dataset 來進行。
一個使用了這些參數的自定義鉤子樣例:
<div id="hook-arguments-example" v-demo:hello.a.b="message"></div> Vue.directive('demo', {bind: function (el, binding, vnode) {var s = JSON.stringifyel.innerHTML ='name: ' + s(binding.name) + '<br>' +'value: ' + s(binding.value) + '<br>' +'expression: ' + s(binding.expression) + '<br>' +'argument: ' + s(binding.arg) + '<br>' +'modifiers: ' + s(binding.modifiers) + '<br>' +'vnode keys: ' + Object.keys(vnode).join(', ')} })new Vue({el: '#hook-arguments-example',data: {message: 'hello!'} })name: "demo" value: "hello!" expression: "message" argument: "hello" modifiers: {"a":true,"b":true} vnode keys: tag, data, children, text, elm, ns, context, functionalContext, key, componentOptions, child, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce
4.函數簡寫
大多數情況下,我們可能想在 bind 和 update 鉤子上做重復動作,并且不想關心其它的鉤子函數。可以這樣寫:
Vue.directive('color-swatch', function (el, binding) {el.style.backgroundColor = binding.value })5.對象字面量
如果指令需要多個值,可以傳入一個 JavaScript 對象字面量。記住,指令函數能夠接受所有合法類型的 Javascript 表達式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div> Vue.directive('demo', function (el, binding) {console.log(binding.value.color) // => "white"console.log(binding.value.text) // => "hello!" })路由
1.前端路由的工作方式
用戶點擊了頁面上的路由鏈接
導致URl地址欄中的Hash值發生了變化
前端路由監聽到了Hash地址變化
前端路由把當前的 Hash 地址對應的組件渲染到瀏覽器中
?
2.底層原理
利用 windows.onhashchange 來監聽hash地址的變化,綁定動態組件實現路由效果
3.路由配置安裝
//導入Vue和 VueRouter 的包 import Vue from 'vue' import VueRouter from 'vue-router' //調用Vue.use()函數,把VueRouter 安裝為 Vue 的插件 Vue.use(VueRouter)//創建路由的實例對象 const rooter = new VueRouter()//向外共享 export default rooter //main.js import Vue from 'vue' import App from './App.vue' //導入路由模塊,拿到實例對象//在進行模塊導入的時候,如果給定的是文件夾,則默認導入這個文件夾下,名字叫做index.js的文件import router from '@/router/index.js'// 導入 bootstrap 樣式 import 'bootstrap/dist/css/bootstrap.min.css' // 全局樣式 import '@/assets/global.css'Vue.config.productionTip = falsenew Vue({render: h => h(App),//把路由實例對象掛載router: router }).$mount('#app')4.路由的重定向
路由的重定向指的是:用戶在訪問地址A的時候,強制用戶跳轉到地址C,從而展示特定的組件頁面。通過路由規則的redirect屬性,指定一個新的路由地址,可以很方便地設置路由的重定向。
const router = new VueRouter({routes: [//當用戶訪問 / 的時候,通過redirect 屬性跳轉到 /home 對應的路由規則{path:'/',redirect:'/home'},{ path: '/home', component: Home },{ path: '/movie', component: Movie },{ path: '/about', component: About }] })5.嵌套路由
通過children 屬性聲明子路由規則
//index.js{path: '/about',component: About,redirect: '/about/tab1',//子路由規則children: [{ path: 'tab1', component: Tab1 },{ path: 'tab2', component: Tab2 }]} //about.vue<router-link to="/about/tab1">Tab1</router-link><router-link to="/about/tab2">Tab2</router-link><hr /><router-view></router-view>默認子路由:如果 children 數組中,某個路由規則的 path 值為空字符串,則這條路由規則,叫做 “ 默認子路由 ”
6.動態路由匹配
動態路由匹配 | Vue Router
{ path: 'userinfo/:id', component: UserDetail, props: true } //動態參數項 props傳值7.聲明式導航&編程式導航
1.在瀏覽器中,點擊鏈接實現導航的方式,叫做聲明式導航。
2.在瀏覽器中,調用API方法實現的導航的方式,叫做編程式導航。例如
在普通網頁中調用location.href跳轉到新頁面的方式,屬于編程式導航。vue-router 中的編程式導航API
this.$router.push('hash地址')
跳轉到指定的地址,并增加一條瀏覽記錄
this.$router.replace('hash地址')
跳轉到指定的地址,并替換掉當前的瀏覽記錄
this.$router.go(數值n)
可以在瀏覽歷史中前進和后退
如果前進、后退的層數超過最大限制,則原地不動
this.$router 的簡化用法
$router.back() $router.forward()
導航守衛
1.全局前置守衛
每次發生路由的導航跳轉時,都會觸發全局前置守衛。因此,在全局前置守衛中,程序員可以對每個路由進行訪問權限的控制:
const router = new VueRouter({...})//調用路由實例對象的 beforeEach 方法,即可聲明“全局前置守衛” //每次發生路由跳轉的時候,都會自動觸發 fn 這個“回調函數” router.beforeEach(fn)2.回調函數中接受的三個實參
router.beforeEach((to,from,next)=>{//to 是將要訪問的路由的信息對象//from 是將要離開的路由的信息對象//next 是一個函數,調用next()表示放行,允許這次路由導航 })?
總結
- 上一篇: 气象基础知识matlab,气象类专业Ma
- 下一篇: c语言中合法整型常量负号,C语言中整型常