事件循环、webpack、vue<前端学习笔记>
async/await
使用注意事項
EventLoop
同步任務和異步任務
為了防止某個耗時任務導致程序假死的問題,JavaScript把待執行的任務分為了兩類:
- 又叫做非耗時任務,指的是在主線程上排隊執行的那些任務
- 只有前一個任務執行完畢,才能執行后一個任務
- 又叫做耗時任務, 異步任務由JavaScript委托給宿主環境
- 當異步任務執行完成后,或通知JavaScript主線程執行異步任務的回調函數
基本概念
JavaScript 主線程從“任務隊列”中讀取異步任務的回調函數,放到執行棧中依次執行。這個過程是循環不斷的,所以整個的運行機制又稱為EventLoop(事件循環)
Webpack
打包慢的原因
- 從0構建依賴
- 磁盤讀取對應的文件到內存,webpack開始加載
- 再用對應的loader進行處理
- 將處理完的內容,輸出到磁盤指定的目錄
I/O過程十分緩慢
問題解決
- webpack-dev-server
起一個開發服務器,緩存一些已經打包過的內容,只重新打包修改的文件,最終運行在內存中給瀏覽器使用(檢測文件變更,不輸出到dist)
webpack 開發服務器,把代碼運行在內存中,自動更新,實時返回給瀏覽器顯示
webpack-dev-server 使用
devServer: {// contentBase: __dirname, -- 請注意,這種寫法已棄用static: {directory: path.join(__dirname, "/dist"),},// port: "8088", // 設置端口號為8088hot: true, // 文件修改后實時刷新historyApiFallback: true, //不跳轉},mode:'development'babel配置
{test: /\.js$/,exclude: /(node_modules|bower_components)/, // 不匹配這些文件夾下的文件use: {loader: 'babel-loader', // 使用這個loader 處理js文件啊// options: { // 加載器選項// presets: ['@babel/preset-env'] /// 預設:@babel/preset-env 降級規則-按照這里的規則降級我們的js語法 寫到.babelrc中即可// }}} <!-- .babelrc 文件設置降級規則--> {"presets": ["env", "react"] }webpack總結回顧
- Webpack 有什么用?
打包整合壓縮轉譯你的代碼
- Webpack 本質?
第三方的包,需要下載到當前工程
- Webpakck 基礎使用
- Webpack 默認入口和出口
-
編寫代碼是開發環境 – 運行的都是打包后的代碼
-
webpack-插件:更多功能
- webpack-加載器:識別處理更多不同類型文件
原本只能識別js文件
VUE
v-for 操作DOM
循環出新的虛擬DOM結構,和舊的虛擬DOM結構對比,嘗試復用標簽就地更新內容
渲染樹構建(renderTree)
渲染樹是dom樹結合css樹形成的一個新的樹。當renderTree構建完畢后,瀏覽器會根據它去繪制頁面。
特點:
- 渲染樹每個節點都有自己的樣式。
- 不包含隱藏節點(display: none)、不需要繪制的節點(html/head/style/title),這些節點在renderTree形成之前就會被剔除。
- visibility: hidden相對應的節點是包含在渲染樹上的,因為它影響布局(layout)。
- 渲染樹上的每一個節點都會被當成一個盒子,具有內容填充、邊距、邊框、位置、大小及其它樣式。
虛擬DOM是什么
本質就是一個JS對象,保存DOM關鍵信息
虛擬DOM好處
提高DOM更新的性能,不頻繁操作真實DOM,在內存中找到變化部分,再更新真實DOM(打補丁)
diff算法如何比較新舊虛擬DOM
- 同級比較
- 根元素變化,刪除重新建立整個DOM樹
- 根元素未變,屬性改變,DOM復用,只更新屬性
v-for設置key
討論數據項和DOM元素的問題
-
無key則就地更新(復用相同類型的標簽,造成渲染錯誤 – 數據項對應錯誤的元素)
-
有key屬性,基于key的來比較新新舊虛擬DOM,移除key不存在元素
- 用索引設置key的問題: 新增數據項及其之后的數據項 對應的key:index對比于舊的虛擬DOM樹都發生了變化,都需要重新渲染,渲染效率低
- 用其它唯一標識做key,數據項對應的key不發生改變,則不用重新渲染,只需要重新渲染新增的數據
v-for 通過 key 值來提升渲染效率的。
Vue過濾器
轉換格式,過濾器就是一個函數,傳入值返回處理后的值
- 過濾器只能用在,插值表達式和v-bind動態屬性里面
- 字符串翻轉,“輸入hello, world”,輸出“dlrow ,olleh“
- 字母轉大寫,輸入”hello“,輸出”HELLO“
- 定義過濾器
- 使用
計算屬性
有緩存減少計算
- 完整語法
數組 every函數
查找數組里“不符合”條件,直接返回false
可以判斷某些元素的屬性是否同時滿足某一條件,有一個不滿足返回false
// 全選按鈕和單選按鈕的相互影響實現 computed:{isAll:{set(val){// 全選框選中 狀態傳入this.arr.forEach(obj => obj.c = val)},get(){// 判斷是否多選按鈕是否全選中return this.arr.every(obj => obj.c === true)}} }偵聽
watch
// 目標:偵聽name值的改變watch:{name(newVal,oldVal){// 變量名對應值改變 這里自動觸發console.log(newVal,oldVal)} }- 深度偵聽
小結
1. 觸發v-for更新監測
能改變 原數組 的 數組方法
push() / pop() /shift() /unshift() / splice() / sort() /reverse()..想要影響v-for更新,解決方案:
- 覆蓋原數組
- this.$set() - 只改變某一個值
2. 虛擬DOM
JS對象 - 保存DOM關鍵信息
提高性能,真實DOM屬性太多,沒辦法快速的找到誰變化了
template => 虛擬DOM => 真實DOM
3. 具體如何把虛擬DOM替換到真實DOM上的?
diff算法:(比較新舊DOM的差異)
(1): 新舊DOM - 同級比較
- 根標簽改變 -> (決定)刪除整個DOM重新創建 -> 更新真實DOM
- 根標簽未變,屬性變了 -> 復用此標簽,只更新屬性 ->更新真實DOM
- 跟標簽未變,屬性未變,子/內容改變
- 無Key -> (比較新舊DOM差異)-> 盡可能復用標簽(就地更新)
- 有Key -> (以Key來比較新舊DOM的差異) -> 創建新的標簽到真實DOM
組件通信
EventBus
- 語法
- src/EventBus/index.js - 創建空白Vue對象并導出import Vue form 'vue' // 導出空白對象 export default new Vue()
- 在要接收值的組件(List.vue)import eventBus from "../EventBus";export default {created(){eventBus.$on('事件名',函數體)} }
- 在要傳遞值的組件(MyProduct.vue)import eventBus from "../EventBus";export default{methods:{kanFn(){eventBus.$emit('事件名',函數體)}} }
Vue生命周期-鉤子函數
Vue框架內置函數,隨著組件的生命周期階段,自動執行
- 作用:特定的時間點,執行特定的操作
- 場景:組件創建完畢后,可以在created 生命周期函數中發起Ajax請求,從而初始化data數據
- 分類:4大階段,8個方法
1. 初始化階段
方法: brforeCreate / created
new vue() – Vue實例化(組件也是一個小的Vue實例)
Init Event & Lifecycle – 初始化事件和生命周期函數
beforCreate\color{red}{beforCreate}beforCreate – 生命周期鉤子函數被執行(無data)
Init injections & reactivity – Vue內部添加data和methods等
created\color{red}{created}created – 生命周期鉤子函數被執行,實例創建(有data)
接下來是編譯模板階段 – 開始分析
Has el option? – 是否有el選項 --檢查要掛到那里
- 沒有,調用$mount()方法
- 有,繼續檢查template 選項 (template里面是模板語法-v-for… 會被編譯為虛擬DOM)
2. 掛載
方法:beforeMount / mounted
template選項檢查
- 有 --編譯template返回render渲染函數
- 無 –編譯el選項對應標簽作為template(要渲染的模板)
虛擬DOM掛載成真實DOM之前
beforeMount\color{red}{beforeMount}beforeMount – 生命周期鉤子函數被執行
Create vm.$el and repalce "el" with it – 把虛擬DOM和渲染的數據一并掛到真實DOM上
真實DOM掛載完畢
mounted\color{red}{mounted}mounted --生命周期鉤子函數被執行(獲取DOM)
3. 更新
方法:beforeUpdate / updated
當data里的數據改變,更新DOM之前
beforeUpdate\color{red}{beforeUpdate}beforeUpdate – 生命周期鉤子函數被執行
Virtual DOM re-render and patch – 虛擬DOM重新渲染,打補丁到真實DOM
updated\color{red}{updated}updated – 生命周期鉤子函數被執行
當有data數據被改變 – 重復這個循環
4. 銷毀
方法:beforeDestroy / destroy
當$destroy()被調用 – 比如組件DOM被移除 (例v-if)
beforeDestroy\color{red}{beforeDestroy}beforeDestroy – 生命周期鉤子函數被執行
拆卸數據監視器、子組件和事件偵聽器
實例銷毀后,最后觸發一個鉤子函數
destroyed\color{red}{destroyed}destroyed --生命周期鉤子函數被執行
axios使用
http://www.axios-js.com/
特點:
- 支持客戶端發送Ajax請求
- 支持服務端Node.js 發送請求
- 支持Promise相關用法
- 支持請求和響應的攔截器功能
- 自動轉換JSON數據
ajax => 一種前端異步請求后端的技術,委托瀏覽器的網絡線程(XMLHttpRequest)
axios => 基于原生ajax + Promise技術封裝通用于前后端的請求庫
axios全局配置
配置基礎地址,統一管理
- 可以在官網看到axios的很多默認配置 http://www.axios-js.com/
- 修改請求url/ 以后的請求都不用帶前綴基地址了 – 運行時,axios的baseURL會自動拼在前面
$refs和 $nextTick使用
$refs可以獲取標簽和組件
// 獲取組件并調用其方法 mounted(){this.$refs.de.fn() }$nextTick()
vue更新DOM是異步的,方法內部執行到修改data 但非同步更新DOM,如果要獲取DOM更新后的數據,使用$nextTick()
$nextTick()返回Promise對象,可以使用語法糖async / await
<p ref="myP">{{count}}<p/> <button @click="getCount">點擊count+1 并馬上輸出p標簽中的數據</button> export default{data(){return {count:0}},methods:{getCount(){this.count++; // Vue檢測數據更新,開啟一個DOM更新隊列(異步任務)// console.log(this.$refs.myP.innerHTML) // 只能獲取到更新之前的內容// 可以更新的鉤子函數內實現,但為了代碼邏輯性使用$nextTick()this.$nextTick(()=>{console.log("DOM更新后觸發$nextTick函數")console.log(this.$refs.myp.innerHTML)})},async getCountAsync(){this.count++;await this.$nextTick();console.log(this.$refs.myp.innerHTML)}},// 鉤子函數mounted(){}, }組件name屬性使用
組件name可用作注冊組件名字
組件
動態組件
:is =“變量組件名”
<component :is="comName"></component> import UseName from '../components/UserName' export default{data(){return {comName:"UserName"}},components:{UseName} }組件緩存(避免切換時被銷毀)
Vue內置的keep-alive組件 包起來要頻繁切換的組件
<keep-alive><!-- Vue 內置的組件component,可用動態顯示組件 --><component :is="comName"></component> </keep-alive>組件緩存后激活(切換回)和非激活(未切換回)
activated() --激活時觸發
deactivated() --失去激活狀態觸發
組件插槽
組件中有一個標簽
使用組件時,組件標簽中間的內容會顯示到
具名插槽
一個組件內有多處需要傳入外部標簽的位置
語法:
插槽作用域
使用插槽時,想用到子組件內的變量
- scope={row:defaultObj}
自定義指令
獲取標簽,拓展額外功能
- 全局注冊-語法
- 局部注冊-語法
Vue-Router
單頁富文本(SPA):所有功能在一個html頁面上實現,局部刷新
前端路由作用:實現業務場景切換
- 優點:
- 整體不刷新頁面,用戶體驗更好
- 數據傳遞容易,開發效率高
- 缺點:
- 開發成本高(需要學習專門知識)
- 首次加載速度慢,不利于SEO
組件分類
- src/views文件夾下的頁面組件 - 頁面展示 - 配合路由使用
- src/components/下的復用組件 - 展示數據/用于復用
使用
// 1.引入第三方包 import VueRouter from "vue-router" // 2.注冊全局組件 Vue.use(VueRouter) // ------------------------------------- // 3.添加規則數組 //統一管理路由名稱 RouterNames = {Home = "Home",List = "List",Detail = "Detail" } const routers = [{path: '/',name: RouterNames.Home,component: HomeView,// 輔助屬性 可自定義完成一些功能meta: {depth:1}},{path: '/list',name: RouterNames.List, component: List,meta: {depth:2}},{path: '/detail/:id',name: RouterNames.Detail, component: Detail,meta: {depth:3}} ] // ---------------------------------------- // 4.生成路由對象 const router = new VueRouter({routers, // routers是固定key(傳入規則數組)mode:"history" // # -- hash路由(以后上線需要服務器端支持,否則找的是文件夾) }) // 5.路由對象注入到vue實例中,this可以訪問$route和 $router new Vue({router,render:h=>h(App), }).$mount('#app') // 6.設置掛載點 導航頁面顯示的位置 <router-view/>聲明式導航_基礎使用
目標:可用組件router-link 來替代a標簽
聲明式導航_跳轉傳值
1.不帶參數 <router-link :to="{name:'home'}" /> <router-link :to="{path:'/home'}" /> //router-link中鏈接如果是'/'開始就是從跟路由開始,如果開始不帶'/',則從當前路由開始 2.帶參數 <router-link :to="{name:'home',params:{id:1}}" /> //params傳參數(類似post) //路由里面配置path:"/home/:id" 或者 path:"/home:id" //冒號用params取參,用"/:"拼接 //不配置path,刷新頁面id會保留 //html取參 $route.params.id //script 取參 this.$route.params.id //params是path的一部分,所以params和name一起使用,不能和path一起使用<router-link :to="{name:'home',query:{id:1}}" /> 或者 <router-link :to="{path:'home',query:{id:1}}" /> //query傳參數(類似get,url后面會顯示參數) //路由可不配置 因為帶參數了 //html 取參 $route.query.id // script 取參 this.$route.query.id重定向
redirect
const routes = [{path:"/",redirect:"/find"},{path:"/find",component:Find} ]路由未命中_404
找不到路徑給提示頁面
path:"*"路由按順序查找,放最后
const routes = [{path:"/",redirect:"/find"},{path:"/find",component:Find},......{path:"*",component:NotFound} ]編程式導航_基礎使用
目標:用JS代碼來進行跳轉
語法:path或者name任選一個
this.$router.push({path:"路由路徑", // 都去 router/index.js 定義name:"路由名" // 在網頁地址欄看不見 })編程式導航_跳轉傳參
目標:用JS跳轉路由,傳參
語法:query或者params任選一個
this.$router.push({path:"路由路徑", name:"路由名",query:{"參數名":值}params:{"參數名":值})路由嵌套和守衛
路由嵌套
在現有的一級路由下,再嵌套二級路由
children屬性
const routes = [{path:"/",redirect:"/find"},{path:"/find",component:Find,children:[{path:"ranking",component:Ranking}]} ]路由守衛
正如其名 ! vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航 、有多種機會植入路 由導航過程中, 全局的, 單個路由獨享的, 或者組件級的
判斷登錄狀態
是與路由相關的函數
完整的導航解析流程
- 導航被觸發
- 在失活的組件里調用離開守衛
- 調用全局的 beforeEach 守衛
- 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)
- 在路由配置里調用 beforeEnter
- 解析異步路由組件
- 在被激活的組件里調用 beforeRouteEnter
- 調用全局的 beforeResolve 守衛 (2.5+)
- 導航被確認
- 調用全局的 afterEach 鉤子
- 觸發 DOM 更新
- 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數
next必須調用
- next(): 進行管道中的一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed(確認)
- next(false): 中斷當前的導航 。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕)、那么 URL 地址會重置到 from 路由對應的地址
- next('/') 或者 next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航 。你可以向 next 傳遞任意位置對象,且允許設置諸如 replace: true 、name: ‘home’ 之類的選項,以及任何用在 router-link 的 to prop 或 router.push 中的選項。
h : '/foo ',
component : Foo,
beforeEnter : (to, from, next) => {
// …
}
}
]
})
// 組件內
const Foo = {
template : 、…、,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 this
// 因為當守衛執行前組件實例還沒被創建
},
beforeRouteupdate (to, from, next) {
// 在當前路由改變 但是該組件被復用時調用
// 舉例來說,對于一個帶有動態參數的路徑 /foo/:id 在 /foo/1 和 /foo/2 之間跳轉的時候 // 由于會渲染同樣的 Foo 組件,因此組件實例會被復用,而這個鉤子就會在這個情況一被調用。
// 可以訪問組件實例 “this”
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用
// 可以訪問組件實例 、this、
}
}
總結
以上是生活随笔為你收集整理的事件循环、webpack、vue<前端学习笔记>的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unix/Linux编程:Interne
- 下一篇: html5倒计时秒杀怎么做,vue 设