一、IDEA中安裝vue插件
讓idea中編寫vue組件/腳本具有代碼提示、着色等功能
- File -> settings... 打開設置窗口
- 搜索 plugin -> 點擊Marketplace ->搜索vue -> install
- 關於搜不到插件怎么辦?
- 百度一下,有說設置代理的,有說關防火牆的,有說將網絡換成熱點的,我試了下都沒什么卵用,同學們可以試試
- 畢竟我們用的是破解版,實在不能在線安裝的話我們可以進行離線安裝插件
- 當你不能在線安裝,離線安裝Vue插件方法如下
- 進入idea插件市場:https://plugins.jetbrains.com/ ,搜索 vue
- 找到下圖這個vue,點進去
- 切換到版本標簽頁
- 然后根據自己的IDEA版本,下載適合自己IDEA版本的vue插件,我這里的idea是 2019.3.5版本的
- 讓后進入你的idea插件安裝窗口,選擇 插件來源於你的本地磁盤安裝
- 然后找到你剛剛下載的vue插件包,選擇它,點擊ok
- 最后點擊 應用,然后重啟IDEA生效
二、VUE 3 基礎
Vue.js(讀音 /vjuː/, 類似於 view) 是一套構建用戶界面的漸進式框架。
Vue 只關注視圖層, 采用自底向上增量開發的設計。
Vue 的目標是通過盡可能簡單的 API 實現響應的數據綁定和組合的視圖組件。
官方文檔:https://v3.cn.vuejs.org/api/
漸進式框架?
- 就是一開始不需要你完全掌握它的全部功能特性,可以后續逐步增加功能。沒有多做職責之外的事情
例如,使用Angular,必須接受以下東西
- 必須使用它的模塊機制
- 必須使用它的依賴注入
- 必須使用它的特殊形式定義組件
所以Angular是帶有比較強的排它性的,如果你的應用不是從頭開始,而是要不斷考慮是否跟其他東西集成,這些主張會帶來一些困擾
又例如,使用React,你必須理解
- 函數式編程的理念
- 需要知道它的副作用
- 什么是純函數
- 如何隔離、避免副作用
它的侵入性看似沒有Angular那么強,主要因為它是屬於軟性侵入的
1、安裝方式
1.1、直接引入
<!--引入vue js文件-->
<script type="text/javascript" src="./js/vue-3.2.4.global.js"></script>
2、模板語法
Vue.js 使用了基於 HTML 的模板語法,允許開發者聲明式地將 DOM 綁定至底層 Vue 實例的數據。
Vue.js 的核心是一個允許你采用簡潔的模板語法來聲明式的將數據渲染進 DOM 的系統。
結合響應系統,在應用狀態改變時, Vue 能夠智能地計算出重新渲染組件的最小代價並應用到 DOM 操作上。
使用格式
- options一個js對象,后面會詳細介紹它
- element 此vue模板語法應用於指定的element元素上
Vue.createApp(options).mount(element);
2.1、簡單示例
- html部分
<!--引入vue js文件-->
<script type="text/javascript" src="./js/vue-3.2.4.global.js"></script>
<body id="app">
姓名:{{name}} <br/>
調用getName方法:{{getName()}}
</body>
- js部分
- data屬性 :重要,數據綁定
- methods屬性:重要,函數綁定
<script>
//每一個vue應用都需要,創建一個vue對象
let app = Vue.createApp({
//數據綁定
data:function(){
return {
name:'張三'
};
},
//函數綁定
methods:{
getName:function(){
return "function--"+this.name;
}
}
});
//該vue對象內容渲染(掛載)到哪個個元素上
//指定元素時,可使用類似jquery選擇器的表達式
app.mount('#app')
</script>
2.2、vue指令
2.2.1、渲染html
2.2.1.1、v-html
渲染指定文本為html
2.2.1.2、v-show
true則顯示,false隱藏
2.2.2、屬性綁定
2.2.2.1、v-bind:屬性名
用於將數據對象中指定的變量綁定到html元素屬性值上
v-bind:xxx = "" 可縮寫為 :xxx = ""
示例1:
v-bind:class //綁定class屬性值
v-bind:href //綁定href屬性值
v-bind:value //綁定value屬性值
示例2:
//綁定對象
v-bind:class="{'clsName':boolean}" //boolean為true,那么使用clsName樣式,為false不會使用clsName這個樣式
//綁定數組
v-bind:class="['clsName1','clsName2'...]"
//內聯樣式綁定對象
v-bind:style="{color:'red',fontSize:'20px'}"
2.2.3、雙向數據綁定
2.2.3.1、v-model
雙向數據綁定,使用於 input、select、textarea、checkbox、radio元素上,用於更改input框中的值同時vue也會修改js對象中綁定的變量的值
常用修飾符
- .number//將文本框輸入的如果是正確的數字,那么會轉換為number類型給變量,不是正確的數字則轉換失敗,變量值NaN
- .trim //將文本框輸入的字符串去掉2端空格后再給變量
示例1:修改input框中的值,看看變化
- html
<body id="app">
姓名:{{name}} <br/>
<input v-model="name"/>
</body>
- options對象
{
//數據綁定
data:function(){
return {
name:'張三'
};
}
}
示例2:配合修飾符使用
2.2.4、流程控制指令
2.2.4.1、條件
v-if ...
v-else-if ...
v-else ...
示例:
2.2.4.2、循環
//遍歷數組
v-for="obj in 數組"
//遍歷對象
v-for="(key,value,index) in 對象"
//遍歷數字
v-for="n in 10"
示例:
2.3、數據對象和方法對象
- options對象如下
{
//數據對象
data(){
return {
//此處可自定義屬性,被掛載的html元素可直接使用這里面的屬性
}
},
//方法對象
methods:{
//此處可自定義方法,被掛載的html元素可直接調用這里面的方法
}
}
示例:
2.4、計算屬性
和methods功能幾乎一樣
computed(計算) 與 methods(方法)區別?
- computed基於瀏覽器緩存,只有依賴的屬性值發生變化時才會調用函數重新計算
- methods 只要相關dom被渲染,就會調用
示例:
- options對象如下
//app對象如下
{
data:function(){
return {
//狀態
status:1
};
},
computed:{
//計算屬性
statusZh:function(){
//this 訪問Vue自身對象
if(this.status == 1){
return '啟用';
}else{
return '禁用';
}
}
}
}
- html中使用它
//使用方式
{{statusZh}}
2.5、過濾器
- html中使用過濾器
{{數據 | dateFormat(p1,p2...) }}
- options對象如下
{
filters:{
//過濾器函數
dateFormat:function(value,p1,p2...){
}
}
}
示例1:將字符串轉大寫的過濾器
示例2:將字符串數組以指定的 分割符拼接起來 的過濾器
示例3:將時間戳 轉換為指定格式的字符串的 過濾器
2.6、監聽
監聽指定屬性發生變化
示例:
- options對象如下
{
data:function(){
return {
//計數
count:1
};
},
watch:{
//監聽count變量變化
//newVal為變化后的新值,oldVal為之前的值
count:function(newVal,oldVal){
console.info('新值:',newVal,'舊值:',oldVal);
}
}
}
2.7、事件綁定
當觸發指定事件時,會調用綁定的函數
使用范例:
v-on:click="" //綁定點擊事件 v-on:blur="" //綁定鼠標聚焦事件 ....
縮寫:
v-on:xxx ="" 可縮寫為 @xxx = ""
常見的事件修飾符
- .stop //阻止事件冒泡
//示例,這樣寫會阻止點擊事件冒泡(傳遞)到父元素上
@click.stop=""
- .self //只監聽自身元素所觸發的事件
//示例,這樣寫 子元素冒泡上來的點擊事件就無法觸發它調用的函數
@click.self = "func1()"
示例1:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--引入vue js文件-->
<script type="text/javascript" src="./js/vue-3.2.4.global.js"></script>
<body id="app">
<div style="width: 500px;height: 100px;border: 2px solid red"
@click="fuc1">
div1
<div style="width: 250px;height: 50px;border: 2px solid black"
@click="fuc2('我的參數')">
div2
</div>
</div>
</body>
<script>
//每一個vue應用都需要,創建一個vue對象
let vm = Vue.createApp({
//函數綁定
methods:{
fuc1:function(event){
console.info("div1被點擊");
console.info("如果綁定時只指定了函數名稱,那么被綁定的函數參數可以獲取原生的js事件對象")
console.info("event:",event)
},
fuc2:function(p1){
console.info("div2被點擊");
console.info("如果綁定時只指定了參數值,那么被綁定的函數可以獲取傳遞過來的參數值")
console.info("p1:",p1)
}
}
});
//該vue對象內容渲染(掛載)到哪個個元素上
//指定元素時,可使用類似jquery選擇器的表達式
vm.mount('#app')
</script>
</html>
示例2:配合事件修飾符使用,沿用上面的例子,html如下
<body id="app">
<div style="width: 500px;height: 100px;border: 2px solid red"
@click.self="fuc1">
div1
<div style="width: 250px;height: 50px;border: 2px solid black"
@click.stop="fuc2('我的參數')">
div2
</div>
</div>
</body>
2.8、組件
組件(Component)是 Vue.js 最強大的功能之一。
組件可以擴展 HTML 元素,封裝可重用的代碼。
注意:這里要額外拓展ES6中 import、export語法
- a.js 文件中定義了一個對象,使用export可將此對象導出
let obj = { name:"張三" } //導出obj對象 export default obj;
- index.html中導入此對象
- 注意設置:type="module" 才能使用import語句
<!-- //注意:要使用import語句,必須設置script 的type為 module,否則會報錯,script的type默認為text/javascript --> <script type="module"> //import 為ES6 語法,可引入其他js文件 import obj from "./a.js"; //打印看看 console.info('obj:',obj); </script>
2.8.1、全局組件
注:示例3重要,必須示例
示例1:簡單注冊
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--引入vue js文件-->
<script type="text/javascript" src="./js/vue-3.2.4.global.js"></script>
<body id="app">
<!--使用組件-->
<global></global>
</body>
<script>
//每一個vue應用都需要,創建一個vue對象
let app = Vue.createApp({
});
//注冊全局組件
app.component("global",{
template:"<h2>我是全局組件,一經注冊,Vue中無論哪里,都可以使用</h2>"
});
//該vue對象內容渲染(掛載)到哪個個元素上
//指定元素時,可使用類似jquery選擇器的表達式
//其實這個被掛載的app元素,就是整個vue中的根組件
app.mount('#app')
</script>
</html>
示例2:制作一個頁頭的全局組件
Header.js內容如下
//頁面內容
let html = `
<div class="header">
{{desc}}
</div>
<!--注意:這里面寫style是沒有用的-->
<style type="text/css">
.header{
border: 1px solid red;
width: 100%;
height: 50px;
}
</style>
`;
//組件對象
let Header = {
//模板字符串
template:html,
data:function(){
return {
desc:"我是頁頭"
}
}
};
//默認導出 Header對象
export default Header;
html使用組件代碼如下
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
<style type="text/css">
.header{
border: 2px solid red;
width: 100%;
height: 50px;
}
</style>
</head>
<!--引入vue js文件-->
<script type="text/javascript" src="./js/vue-3.2.4.global.js"></script>
<body id="app">
<!--使用全局組件-->
<hd></hd>
</body>
<script type="module">
//import 為ES6 語法,可引入其他js文件
//注意:要使用import語句,必須設置script 的type為 module,否則會報錯,script的type默認為text/javascript
//導入Add.js 中的對象
import Header from "./js/Header.js";
//每一個vue應用都需要,創建一個vue對象
let app = Vue.createApp({});
//注冊全局組件 ,注意:組件id不能與已有的標簽同名
app.component("hd",Header);
//該vue對象內容渲染(掛載)到哪個個元素上
//指定元素時,可使用類似jquery選擇器的表達式
//其實這個被掛載的app元素,就是整個vue中的根組件
app.mount('#app')
</script>
</html>
示例3:制作一個頁尾的全局組件
注:
- 由於ES6提供的 import 語句只能引入的js文件,然而我們在js文件中編寫html代碼極為不便,而且樣式也不好書寫
- 有大佬寫了一個 vue3-sfc-loader.js(vue組件加載器)的腳本,用於加載vue組件,只要你按照規定的格式書寫組件並注冊即可
- 編寫 Footer.vue組件,代碼如下(注意規則)
- template 標簽中包含的是html模板代碼
- script 標簽中包含的是js代碼
- style 標簽中包含的css代碼,scoped屬性指定此style為局部作用
<!--html模板-->
<template>
<div class="footer">
{{desc}}
</div>
</template>
<!--js腳本-->
<script>
let Footer = {
data:function(){
return {
desc:"我是頁腳"
}
}
};
//特別注意:使用http-vue-loader加載器加載vue組件時不能用export來導出對象
//export default Footer;
//導出對象
module.exports = Footer;
</script>
<!--css樣式
scoped :局部作用
-->
<style scoped>
.footer{
width: 100%;
margin-top: 100px;
border: 2px solid red;
height: 50px;
}
</style>
- html中注冊組件並使用,代碼如下
- 注意1:vue-3.2.4.global.js、vue3-sfc-loader.js、vue3-loader-helper.js必須按照順序引入
- 注意2:注冊由loadModule函數加載的組件,必須使用 Vue.defineAsyncComponent來異步注冊組件
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
<style type="text/css">
.header{
border: 2px solid red;
width: 100%;
height: 50px;
}
</style>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<!--使用全局組件-->
<hd></hd>
<ft></ft>
</body>
<script type="module">
//import 為ES6 語法,可引入其他js文件
//注意:要使用import語句,必須設置script 的type為 module,否則會報錯,script的type默認為text/javascript
//導入Add.js 中的對象
import Header from "./js/Header.js";
//使用Vue組件加載器 加載我們的 頁腳組件
let Footer = loadModule("./components/Footer.vue");
//每一個vue應用都需要,創建一個vue對象
let app = Vue.createApp({
});
//注冊全局組件 ,注意:組件id不能與已有的標簽同名
app.component("hd",Header);
//異步注冊頁腳組件 為全局組件
app.component("ft", Vue.defineAsyncComponent(function(){
return Footer;
}));
//該vue對象內容渲染(掛載)到哪個個元素上
//指定元素時,可使用類似jquery選擇器的表達式
//其實這個被掛載的app元素,就是整個vue中的根組件
app.mount('#app')
</script>
</html>
2.8.2、局部組件
<div id="app"> <!--使用組件--> <component-a></component-a> <component-b></component-b> </div> <script> //組件A let componentA = { ... }; //組件B let componentB = { ... }; let app = Vue.createApp({ //局部組件注冊 components:{ 'component-a':componentA, 'component-b':componentB } }); app.mount('#app'); </script>
示例1:制作用戶添加表單的局部組件
- Add.vue 代碼如下
//html模板語句部分
<template>
<div class="Add">
<h2>添加頁面</h2>
<form action="#">
<div>
姓名:<input v-model="name"/>
</div>
<div>
年齡:<input v-model="age"/>
</div>
<div>
電話:<input v-model="tel"/>
</div>
<div>
愛好:
<label>
<input v-model="hobbyList" type="checkbox" value="01"/> 游泳
</label>
<label>
<input v-model="hobbyList" type="checkbox" value="02"/> 旅游
</label>
<label>
<input v-model="hobbyList" type="checkbox" value="03"/> 唱歌
</label>
</div>
<div>
<button @click="clkSubmit" type="button">提交</button>
</div>
</form>
</div>
</template>
<!--腳本代碼-->
<script>
//定義組件相關數據以及綁定內容
let add = {
//數據綁定
data: function () {
return {
name: "張三",
age: 18,
tel: "123456789",
hobbyList:['01','02']
}
},
methods:{
//點擊提交按鈕 ,將調用的函數
clkSubmit:function(){
console.info('表單數據-----:');
console.info('name:',this.name);
console.info('age:',this.age);
console.info('tel:',this.tel);
console.info('hobbyList:',this.hobbyList);
}
}
};
//es6語法,使用import引用此文件時,默認導出的js對象為 add對象
export default add;
</script>
<!--css樣式-->
<style>
.Add{
text-align: center;
}
.Add form div{
padding: 5px 5px;
}
</style>
- html中 注冊局部組件並使用代碼如下
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body id="app">
<!--使用局部組件-->
<user-add></user-add>
</body>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<script type="module">
//導入Add組件
let Add = loadModule('./components/Add.vue');
//每一個vue應用都需要,創建一個vue對象
let app = Vue.createApp({
//注冊局部組件
components:{
//異步加載組件
'user-add':Vue.defineAsyncComponent(function(){
return Add;
})
}
});
//其實這個被掛載的app元素,就是整個vue中的根組件
app.mount('#app')
</script>
</html>
2.8.3、組件關系
2.8.3.1、父子組件
Vue是最大的祖父(
app.mount('#app')
這個 app元素就是最大的祖父)組件可以無限嵌套
組件在哪里被使用了,那個被使用的組件就是兒子
2.8.3.2、父子組件通信案例
父組件傳遞數據給子組件:
子組件的options中可定義 props 來接收父組件的傳遞的數據。
子組件options范例
{ props:{ // type可以是:String、Number、Boolean、Array、Object、Date、Function、Symbol(ES6新增的類型,表示獨一無二的值)等類型 p1:{ type:String,//必須是字符串類型 required:true,//要求父組件必須傳遞該屬性值 default:function(){ return "" } //默認是空字符串 }, p2:{ type:Number,//必須是數字類型 default: 100,//如果父組件沒有傳遞值,則默認為100 } } }
- 父組件在子組件標簽上 通過
v-bind:xxx="變量名"
來將數據綁定到子組件對應的屬性上- xxx 為子組件props中定義的屬性名。注意:子組件的屬性名若是駝峰命名綁定時需要轉 - ,下面的案例中會提到
- 變量名可在父組件 data中定義
子組件發送消息給父組件:
- 子組件可利用$emit函數來發送一個事件給父組件,然后在父組件中監聽此事件
/**子組件**/ //第一個參數為事件名稱,后續的參數為傳遞的內容,內容參數可以有多個 this.$emit("eventName",p1...) /**子組件**/ /**父組件**/ //父組件則需要監聽子組件發送的事件,比如監聽子組件的eventName事件,示例如下 <子組件 v-on:eventName="func1"></子組件> //注意,v-on:后面的eventName就是子組件發送的事件名稱 //當子組件發送 eventName 這個事件給父組件時,父組件就會調用 func1這個函數來進行處理 /**父組件**/
案例:曹操和曹丕對話
- 兒子組件-曹丕 Caopi.vue 文件代碼如下
<!--曹丕-->
<template>
<div>
<h2>大兒子:曹丕</h2>
<div>
祖父的告誡:{{fatherSay}}
</div>
<div>
對父親說:<input v-model="tellDad"/>
<button @click="sendMsg">發送</button>
</div>
</div>
</template>
<script >
export default {
//定義屬性,可用於接收父組件傳遞的值
props:{
//定義了一個屬性,名稱為:father-say
"fatherSay":"",
},
data:function(){
//告訴爹的的言語
tellDad:""
},
methods:{
//發送消息給父親
sendMsg:function(){
console.info("*** 曹丕點擊了發送按鈕")
//$emit為發送自定義事件函數
//下面的代碼是自定了 caopiMsg事件,並觸發該事件,而且將tellDad數據傳遞給了該事件
this.$emit("caopiMsg",this.tellDad);
}
}
}
</script>
- 父組件-曹操,html代碼如下
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>祖父:曹操</h2>
<div>
對曹丕說的話:<input v-model="tellCp"/> <br/>
曹丕的回信:{{cpMsg}}
</div>
<hr/>
<!--兒子,曹丕
v-bind:father-say="tellCp" 釋義:
綁定cp組件中 fatherSay 屬性值為 tellCp變量值
特別注意:若子組件定義的屬性名稱為駝峰命名,父組件綁定屬性時要注意 - 轉換
v-on:caopi-msg="caopiMsg" 釋義:
監聽cp組件中caopiMsg事件,若該事件被觸發,則調用methods中caopiMsg函數
特別注意:若子組件定義的事件名稱為駝峰命名,父組件監聽事件時要注意 - 轉換
-->
<cp v-bind:father-say="tellCp" v-on:caopi-msg="caopiMsg"></cp>
</div>
</body>
<script type="module">
//導入CaoPi組件
let Cp = loadModule("./components/CaoPi.vue");
let app = Vue.createApp({
components:{
//異步注冊曹丕組件
Cp:Vue.defineAsyncComponent(function(){
return Cp;
})
},
data:function(){
return {
//曹操對曹丕說的話
tellCp:"",
//接收曹丕消息的變量
cpMsg:""
}
},
methods:{
//曹丕的消息
caopiMsg:function(msg){
this.cpMsg = msg;
console.info("*** 曹丕消息:",msg);
}
}
});
//將app對象掛載(渲染)到指定的dom元素上
let vm = app.mount('#app')
</script>
</html>
2.8.3.3、兄弟組件及通信
在一個組件中同時使用了組件A和組件B,A、B就是兄弟組件
兄弟組件通信范例:沿用上面的例子,在做一個甄姬組件,和曹丕為兄弟組件,且曹丕和甄姬可互相對話
說明:
- 曹丕發消息給甄姬原理:在甄姬在根vue對象掛一個回調函數,曹丕想傳遞消息給甄姬時調用此函數即可
- 甄姬發消息給曹丕原理同上
- Caopi.vue(曹丕組件)完整代碼如下
<!--曹丕-->
<template>
<div>
<h2>大兒子:曹丕</h2>
<div>
祖父的告誡:{{fatherSay}}
</div>
<div>
對父親說:<input v-model="tellDad"/>
<button @click="sendMsg">發送</button>
</div>
<div>
對甄姬說:<input v-model="tellZj"/>
<button @click="sendMsgToZj">發送</button>
<hr/>
甄姬的言語:
</div>
</div>
</template>
<script >
export default {
//定義屬性,可用於接收父組件傳遞的值
props:{
//定義了一個屬性,名稱為:father-say
"fatherSay":"",
},
data:function(){
return {
//告訴爹的的言語
tellDad:"",
//告訴給甄姬的言語
tellZj:""
}
},
methods:{
//發送消息給父親
sendMsg:function(){
console.info("*** 曹丕點擊了發送按鈕")
//$emit為發送自定義事件函數
//下面的代碼是自定了 caopiMsg事件,並觸發該事件,而且將tellDad數據傳遞給了該事件
this.$emit("caopiMsg",this.tellDad);
},
//發送消息給甄姬
sendMsgToZj:function(){
console.info("*** 曹丕發送消息給甄姬")
//根對象,甄姬在根Vue對象掛了一個回調函數,曹丕可通過此回調函數將言語傳遞給甄姬
//let root = this.$root;
console.info('call func',this.$root.callCpTake)
//如果此回調函數存在
if(this.$root.callCpTake){
//調用此函數,並將消息傳遞過去
this.$root.callCpTake(this.tellZj);
}
}
}
}
</script>
- Zhenji.vue(甄姬組件)完整代碼如下
<!--甄姬組件-->
<template>
<div>
<h2>媳婦-甄姬</h2>
曹丕的言語:{{cpMsg}}
</div>
</template>
<script>
export default {
data:function(){
return {
//來自於曹丕的消息
cpMsg:""
}
},
//當組件初始化options完畢后
created:function(){
let self = this;
//this.$root 可獲取到 根Vue對象
//在根對象掛一個回調函數
this.$root.callCpTake = function(msg){
//曹丕說話的回調函數,我們約定曹丕每次說話就調用此函數
self.cpMsg = msg;
}
},
}
</script>
- 曹操組件html完整代碼如下
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>祖父:曹操</h2>
<div>
對曹丕說的話:<input v-model="tellCp"/> <br/>
曹丕的回信:{{cpMsg}}
</div>
<hr/>
<!--兒子,曹丕
v-bind:father-say="tellCp" 釋義:
綁定cp組件中 fatherSay 屬性值為 tellCp變量值
特別注意:若子組件定義的屬性名稱為駝峰命名,父組件綁定屬性時要注意 - 轉換
v-on:caopi-msg="caopiMsg" 釋義:
監聽cp組件中caopiMsg事件,若該事件被觸發,則調用methods中caopiMsg函數
特別注意:若子組件定義的事件名稱為駝峰命名,父組件監聽事件時要注意 - 轉換
-->
<cp v-bind:father-say="tellCp"
v-on:caopi-msg="caopiMsg"
></cp>
<hr/>
<!--媳婦 甄姬-->
<zj></zj>
</div>
</body>
<script type="module">
//導入CaoPi組件
let Cp = loadModule("./components/CaoPi.vue");
//導入ZhenJi組件
let Zj = loadModule("./components/ZhenJi.vue");
let app = Vue.createApp({
components:{
//異步注冊曹丕組件
Cp:Vue.defineAsyncComponent(function(){
return Cp;
}),
//異步注冊甄姬組件
Zj:Vue.defineAsyncComponent(function(){
return Zj;
})
},
data:function(){
return {
//曹操對曹丕說的話
tellCp:"",
//接收曹丕消息的變量
cpMsg:""
}
},
methods:{
//曹丕的消息
caopiMsg:function(msg){
this.cpMsg = msg;
console.info("*** 曹丕消息:",msg);
}
}
});
//將app對象掛載(渲染)到指定的dom元素上
let vm = app.mount('#app')
</script>
</html>
2.8.4、組件生命周期
2.8.4.1、beforeCreate
類型:Function
詳細:在實例初始化之后、進行數據偵聽和事件/偵聽器的配置之前同步調用。
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>頁面內容</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
/*
Vue.createApp 函數會創建Vue對象,當Vue對象創建完畢后
此時僅僅初始化了一些內置事件和生命周期的函數
*/
beforeCreate:function(){
//這個用得不多
//注意:這是 data、methods、watch...等都沒有初始化,這里是無法獲取的
//打印的undefined
console.info('name:',this.name);
}
});
//將app對象掛載(渲染)到指定的dom元素上
app.mount('#app')
</script>
</html>
2.8.4.2、created
類型:Function
詳細:在實例創建完成后被立即同步調用。在這一步中,實例已完成對選項的處理,意味着以下內容已被配置完畢:數據偵聽、計算屬性、方法、事件/偵聽器的回調函數。然而,掛載階段還沒開始,且 $el 屬性目前尚不可用。
注:$el指的是虛擬dom,可通過此虛擬dom訪問html元素
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>頁面內容,姓名:{{name}}</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
/*
當options選項被處理完畢后調用此函數,options處理完畢后意味着 data、methods、watch...等數據都可以獲取到了
但是注意:這時dom還沒有被掛載(渲染),這時是拿不到dom元素的
此函數一般在首次進入頁面需要加載數據時使用
*/
created:function(){
//這里打印的是 “張三”
console.info("name:",this.name);
//這時虛擬dom還未創建,dom也還沒有掛載(渲染),打印的null
console.info("--虛擬dom:",this.$el)
}
});
//將app對象掛載(渲染)到指定的dom元素上
app.mount('#app')
</script>
</html>
2.8.4.3、beforeMount
類型:Function
詳細:在掛載開始之前被調用:相關的 render 函數首次被調用。
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>頁面內容,姓名:{{name}}</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
/*
首次調用render(渲染)函數之前調用
*/
beforeMount:function(){
//$el(虛擬dom)只有在調用render之后才會被創建,所以這里還是打印null
//這個函數一般用得也不算太多
console.info("--虛擬dom:",this.$el)
}
});
//將app對象掛載(渲染)到指定的dom元素上
app.mount('#app')
</script>
</html>
2.8.4.4、mounted
類型:Function
詳細:在實例掛載完成后被調用,這時候傳遞給 app.mount 的元素已經被新創建的
vm.$el
替換了。如果根實例被掛載到了一個文檔內的元素上,當 mounted 被調用時,vm.$el
也會在文檔內。 注意 mounted 不會保證所有的子組件也都被掛載完成。如果你希望等待整個視圖都渲染完畢,可以在 mounted 內部使用vm.$nextTick
注:vm指的是Vue自身對象,即在 data或method中的this
示例:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<!--多直系子元素演示
<h2>生命周期演示</h2>
<div>
頁面內容
</div>-->
<!--一個直系子元素演示-->
<div>
<h2>生命周期演示</h2>
<div>頁面內容</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
/*
#app這個dom元素 掛載(渲染)完畢后調用
這時,虛擬dom($el)已被創建,可以通過虛擬dom訪問html元素
但是,這個頁面可能包含子組件,子組件的元素可能訪問不到
*/
mounted:function(){
//如果被掛載的dom只有一個直系子元素,這里打印的這個直系子元素
//但是當被掛載的dom下有多個直系子元素時(注釋也包括),這里打印首個文本節點
console.info('---通過虛擬dom訪問元素:',this.$el)
//由於這個頁面可能包含子組件,那么子組件的元素如何在這里進行訪問呢?
//利用 vm.$nextTick函數可解決此問題
this.$nextTick(function(){
//當所有dom(包括子組件)掛載(渲染)完畢后,將執行此函數
console.info("---此處訪問子組件元素100%能訪問到")
});
}
});
//將app對象掛載(渲染)到指定的dom元素上
//指定元素時,可使用類似jquery選擇器的表達式
//其實這個被掛載的app元素,就是整個vue中的根組件
app.mount('#app')
</script>
</html>
2.8.4.5、beforeUpdate
類型:Function
詳細:在數據發生改變后,DOM 被更新之前被調用。這里適合在現有 DOM 將要被更新之前訪問它,比如移除手動添加的事件監聽器。
示例:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>
頁面內容
<hr/>
<span>
姓名:{{name}}
</span>
<hr/>
修改name:<input v-model="name"/>
</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
/*
更改數據時觸發
數據改變之后,dom渲染之前調用
*/
beforeUpdate:function(){
//這里打印的name是修改過后的數據
console.info("name值:",this.name);
//獲取span標簽中的文本內容,由於dom還未渲染,所以這個文本內容還是之前的
let text = this.$el.querySelector("span").textContent;
console.info("text,",text);
}
});
//將app對象掛載(渲染)到指定的dom元素上
app.mount('#app')
</script>
</html>
2.8.4.6、updated
類型:Function
詳細:在數據更改導致的虛擬 DOM 重新渲染和更新完畢之后被調用。
當這個鈎子被調用時,組件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。然而在大多數情況下,你應該避免在此期間更改狀態。如果要相應狀態改變,通常最好使用計算屬性或偵聽器取而代之。
注意,updated 不會保證所有的子組件也都被重新渲染完畢。如果你希望等待整個視圖都渲染完畢,可以在 updated 內部使用 vm.$nextTick:
示例:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>
頁面內容
<hr/>
<span>
姓名:{{name}}
</span>
<hr/>
修改name:<input v-model="name"/>
</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
/*
更改數據后,當數據影響的dom渲染完畢后調用此函數
注意:如果受影響更新的有子組件,那么並不能保證子組件也渲染完畢
*/
updated:function(){
//同學們記住一點就好,訪問dom統一在 vm.$nextTick 中就好,因為$nextTick中100%能保證任何dom被渲染完畢
this.$nextTick(function(){
console.info("$nextTick中隨便你訪問子組件的dom還是其他dom,都是能100%保證是渲染過后的")
})
}
});
//將app對象掛載(渲染)到指定的dom元素上
app.mount('#app')
</script>
</html>
2.8.4.7、beforeUnmount
類型:Function
詳細:在卸載組件實例之前調用。在這個階段,實例仍然是完全正常的。
注:什么情況下會使vue組件被
示例:見unmounted
2.8.4.8、unmounted
類型:Function
詳細:卸載組件實例后調用。調用此鈎子時,組件實例的所有指令都被解除綁定,所有事件偵聽器都被移除,所有子組件實例被卸載。
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<body id="app">
<div>
<h2>生命周期演示</h2>
<div>
頁面內容
<hr/>
<span>
姓名:{{name}}
</span>
<hr/>
修改name:<input v-model="name"/>
<hr/>
<button @click="unmountApp">卸載Vue</button>
</div>
</div>
</body>
<script type="module">
let app = Vue.createApp({
data:function(){
return {
name:"張三"
}
},
methods:{
//卸載Vue組件
unmountApp:function(){
//卸載
app.unmount();
}
},
/*
vue組件即將被卸載之前調用
那么一般什么時候會觸發卸載呢?
調用 app的 unmount 函數
*/
beforeUnmount:function(){
//一般這里面可以做一些清理資源的動作,比如:銷毀定時器等
console.info("--卸載之前調用")
},
/**
* vue組件卸載完畢后調用
*/
unmounted:function(){
//一般這里面可以做一些清理資源的動作,比如:銷毀定時器等
console.info("--卸載后調用")
}
});
//將app對象掛載(渲染)到指定的dom元素上
let vm = app.mount('#app')
</script>
</html>
2.9、路由
我們前面要使用組件,有以下三步操作
- 先導入組件
- 注冊組件
- 頁面使用標簽渲染組件
如果我們的頁面使用的組件較少,沒什么組件切換的操作倒是也不顯得麻煩。但是如果我們的組件很多,或者在頁面上需要頻繁的切換各種組件,使用上面的操作就會顯得非常麻煩
這時,我們的路由插件就有用武之地了,它可以將一個vue組件映射為一個url地址,訪問這個被映射的url地址,即可渲染對應的組件
使用示例:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<!--引入路由組件-->
<script src="./js/vue-router-4.0.12.global.js"></script>
<body id="app">
<div>
<h2>路由示例</h2>
<div>
<router-link to="/home">導航Home組件,並渲染它</router-link>
<br/>
<router-link to="/update">導航Update組件,並渲染它</router-link>
<!--傳遞參數-->
<br/>
<router-link :to="toHomeExample1">導航Home組件-params參數</router-link>
<br/>
<router-link :to="toHomeExample2">導航Home組件-query參數</router-link>
</div>
<hr/>
<div>
<!--路由渲染的位置-->
<router-view>
</router-view>
</div>
</div>
</body>
<script type="module">
//導入首頁面組件
let Home = loadModule("./pages/Home.vue");
//導入修改頁面組件
let Update = loadModule("./pages/Update.vue");
//路由配置
const routes = [
{
path:"/home",
//路由名稱
name:"Home",
component:Home
},
{
path:"/update",
component:Update
}
];
//創建一個路由的對象
const router = VueRouter.createRouter({
//內部提供了 history 模式的實現。為了簡單起見,我們在這里使用 hash 模式。
//使用 URL 的 hash 來模擬一個完整的 URL,當 URL 改變時,頁面不會重新加載。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的縮寫
});
let app = Vue.createApp({
data:function(){
return {
//params傳遞參數示例
toHomeExample1:{
//根據路由名稱找組件
name:"Home",
//注意:傳遞params參數必須指定name屬性,否則參數傳遞不過去
params:{id:'123'}
},
//query傳遞參數示例
toHomeExample2:{
//根據路徑找組件
path:"/home",
query:{sex:'女'}
}
}
}
});
//讓Vue應用支持路由這個插件
app.use(router);
//將app對象掛載(渲染)到指定的dom元素上
let vm = app.mount('#app')
</script>
</html>
2.9.1、嵌套路由
示例:
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<!--
特別注意:以下3個文件必須按照順序引入
-->
<!--引入vue js文件-->
<script src="./js/vue-3.2.4.global.js"></script>
<!--引入vue組件加載器腳本-->
<script src="./js/vue3-sfc-loader.js"></script>
<!--引入vue組件加載器幫助文件,此文件內部提供loadModule函數加載組件-->
<script src="./js/vue3-loader-helper.js"></script>
<!--引入路由組件-->
<script src="./js/vue-router-4.0.12.global.js"></script>
<body id="app">
<div>
<h2>路由示例</h2>
<div>
<router-link to="/user/card">查看用戶銀行賬戶信息</router-link>
<br/>
<router-link to="/user/info">查看用戶個人基本信息</router-link>
</div>
<hr/>
<div>
<!--路由渲染的位置-->
<router-view>
</router-view>
</div>
</div>
</body>
<script type="module">
//導入用戶組件
let User = loadModule("./pages/User.vue");
//導入用戶卡片信息組件
let UserCard = loadModule("./pages/UserCard.vue");
//導入用戶個人基本信息組件
let UserInfo = loadModule("./pages/UserInfo.vue");
//路由配置
const routes = [
{
path:"/user",
component:User,
//子路由配置
children:[
{
path:"card",
component: UserCard
},
{
path:"info",
component: UserInfo
}
]
}
];
//創建一個路由的對象
const router = VueRouter.createRouter({
//內部提供了 history 模式的實現。為了簡單起見,我們在這里使用 hash 模式。
//使用 URL 的 hash 來模擬一個完整的 URL,當 URL 改變時,頁面不會重新加載。
history:
VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的縮寫
});
let app = Vue.createApp({
});
//讓Vue應用支持路由這個插件
app.use(router);
//將app對象掛載(渲染)到指定的dom元素上
let vm = app.mount('#app')
</script>
</html>
2.10、axios
Vue 版本推薦使用 axios 來完成 ajax 請求。
Axios 是一個基於 Promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中
使用格式如下:
特別注意:axios作為請求主體發送的數據(config中的data)
默認是會將js對象轉換為json字符串傳遞給服務端的
所以如果默認配置下,config中傳遞了data參數,后端需要獲取請求體中json串並對其進行解析。(如果后端使用了springMVC或spring boot框架,則記得使用 @ResponseBody注解即可)
//創建一個axios實例
let service = Axios.create();
/**
get請求,返回Promise對象
url 為請求地址,config為配置對象
*/
service.get(url,config)
.then(function(resp){...})
.catch(function(err){...})
//post請求
service.post(url,config)
.then(function(resp){...})
.catch(function(err){...})
//put請求
service.put(url,config)
.then(function(resp){...})
.catch(function(err){...})
//delete請求
service.delete(url,config)
.then(function(resp){...})
.catch(function(err){...})
config對象常用參數說明如下:
{
//如果你需要在url拼接參數,可加此屬性
params:{key1:"key1",key2:"key2"},
// `data` 是作為請求主體被發送的數據
// 只適用於這些請求方法 "PUT", "POST", 和 "PATCH"
data: {
key1:"key1",
key2:"key2"
},
// `headers` 是即將被發送的自定義請求頭,比如下面設置請求內容類型為傳統表單的形式
headers: {"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"},
}
如果需要使用Axios跨域請求能傳遞cookie,則需要如下設置
//解決跨域請求cookie不能傳遞問題
axios.defaults.withCredentials = true;
示例:
有3個接口:
接口1:根據用戶id能獲取用戶的 身份證號碼
接口2:根據身份證號碼獲取綁定的銀行卡號
接收3:根據銀行卡號獲取卡上余額
現有一用戶ID,要求獲取該用戶的余額
2.11、Promise
解決以前深陷回調的地獄問題
axios是基於Promise的http庫,能配合promise解決回調地獄問題
我們先來看看promise的基本用法,在來解決上面例子的回調地獄問題
說明:
Promise對象的狀態不受外界影響。Promise 對象代表一個異步操作,有三種狀態:
- pending: 初始狀態,不是成功或失敗狀態。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失敗。
創建一個Promise對象
var promise = new Promise(function(resolve, reject) {
// 對象一旦被創建,就會異步的執行此函數
//此時,Promise對象為 pending狀態
//此處你可以發送ajax請求或做別的事情
/*
比如:我發送一個ajax請求
axios.get('url')
.then(function(resp){
//處理成功,將此 Promise對象修改為fulfilled狀態
resolve(resp);
})
.catch(function(err){
//處理出錯,將此 Promise對象修改為rejected狀態
reject(err);
})
*/
});
//then鏈式
promise.then(function(data){
//如果這個then中無返回值或返回undefined,那么下一個then的data就是undefined
//如果這個then中返回 非Promise 的對象或數據,那么下一個then的data就是這里返回的 對象或數據
//如果這個then中返回 Promise 對象,那么下一個then的data就是 Promise對象中的 resolve回調的數據
}).then(function(data){
})...;
示例一個簡單的鏈式操作:
將前面axios的例子封裝為Promise鏈式操作:
二、NPM方式構建VUE應用
npm 是Node 的模塊管理器,功能極其強大。
它是Node 獲得成功的重要原因之一。
正因為有了npm,我們只要一行命令,就能安裝別人寫好的模塊.
實際上我們工作中常用vue構建項目,其做為一個獨立的前端項目(前后端分離),這時候我們不但要創建一個完美的目錄結構,在vue中可能還要使用到各類第三方工具或組件(如:webpack...等)。這時候我們就需要使用npm方式來安裝vue了。
npm 是Node 的模塊管理器,功能極其強大。我們可以利用它快速完成vue的相關組件安裝。
1、關於webpack
我們接下來學習的vue是使用webpack來打包,所以我們先了解一下webpack是啥玩意兒
1.1、什么是Webpack?
本質上,webpack是一個現代JS應用程序的靜態模塊打包器(module bundle)。
當webpack處理應用程序時,它會遞歸地構建一個依賴關系圖(dependency graph),其中包含應用程序需要的每個模塊,然后將所有這些模塊打包成一個或多個bundle(前端資源,如:css、圖片、json、js...)。
1.2、為什要使用WebPack?
webpack通過讓JS來處理依賴關系和加載順序,而非通過開發者的大腦。
webpack可純粹的在服務端運行來構建漸進增強式的應用。
webpack試圖通過提出一個大膽的想法來減輕開發者的負擔:如果開發過程一部分可以自動處理依賴關系會怎樣呢?若可以簡單地寫代碼,讓構建過程最終只根據需求管理自己會怎樣呢?
webpack的方式是:若webpack了解依賴關系,它會捆綁(打包)在生產環境中實際需要的部分。
- WebPack特性
將依賴樹拆分保證按需加載
保證初始加載的速度
所有靜態資源可被模塊化
整合構建第三方庫和模塊
適合構建大型SPA(單頁應用程序)
場景1
A同學開發了模塊a,B同學開發了模塊b,在頁面下通過如下方式進行引用
<script src="a.js"></script>
<script src="b.js"></script>
這時模塊a,模板b中的代碼都暴露在全局環境中,如果模塊a中定義了一個方法del。同學b並不知道,在模塊b中也定義了一個方法del。這時便造成了命名沖突的的問題。如圖
場景2
C同學開發了一個公共的工具庫utils.js,D同學開發了一個公共的組件tab.js,tab.js依賴utils.js。
同學E需要使用D同學開發的tab.js,就需要通過如下方式引用
<script src="util.js"></script>
<script src="tab.js"></script>
同學E自己也開發了一個dailog.js同時它也依賴util.js。現在頁面同時引用了dialog.js和tab.js,代碼如下
<script src="util.js"></script>
<script src="dialog.js"></script>
<scrpt src="tab.js"></script>
同學E不僅需要同時引用這三個js文件,還必須保證文件之間的引用順序是正確的。同時,從上面的代碼我們無法直接看出模塊與模塊之間的依賴關系,如果不深入tab.js,我們無法知道tab.js到底是只依賴util.js還是dialog.js或者兩者都依賴。隨着項目逐漸增大,不同模塊之間的依賴關系則會變的越來越難以維護也會導致許多模塊中大量的變量都暴露在全局環境中。
為了解決上述這種惡心人的問題,通過使用webpack工具來打包你的前端代碼,讓其幫你分析處理依賴關系、 避免命名污染等一系列問題。
2、環境搭建
2.1、安裝node.js
- 官網:https://nodejs.org/en/download/current/
- 安裝課件提供的node js:node-v16.13.0-x64.msi 文件
- 檢查node js是否安裝成功
- win + r以管理員身份進入命令行窗口,鍵入一下命令可得知 node js是否安裝成功
#查看node js版本
node -v
#查看npm管理器版本
npm -v
2.2、使用npm或cnpm安裝一下模塊
2.2.1、cnpm模塊
npm模塊管理器安裝其他模塊時,一般連接的國外的服務器下載模塊文件進行安裝,由於國內訪問國外網絡可能不好,容易出現下載速度慢或下載超時情況
我們可以安裝cnpm來替代npm模塊管理器,cnpm連接的是國內淘寶鏡像下載文件,速度較快,推薦使用
# npm install 表示調用npm命令的install(安裝)功能 ,來安裝cnpm模塊 ,-g表示全局安裝
npm install cnpm -g
2.2.2、安裝vue模塊
cnpm install vue -g
2.2.3、安裝vue-cli(腳手架構建工具)
它是一個專門為單頁面應用快速搭建繁雜的腳手架
它可以輕松的創建新的應用程序而且可用於自動生成vue和webpack的項目模板。
cnpm install vue-cli -g
2.3、使用vue-cli(腳手架構建工具)構建一個項目
vue-cli構建的項目內置webpack打包工具,它是利用webpack工具來對項目打包
- 創建項目
vue create 項目名稱
Babel是編寫下一代 JavaScript 的編譯器
ESLint 是一個插件化並且可配置的 JavaScript 語法規則和代碼風格的檢查工具
- 運行項目
#進入你剛剛創建的項目目錄
cd 你的項目目錄
#使用npm或cnpm都可以,運行它
cnpm run serve
2.3、目錄說明
使用idea 打開我們構建的基於webpack模板的項目,在此之前
idea 安裝vue插件,該插件讓idea 支持開發vue項目
settings -> plugins ->搜索vue 進行安裝
- 打開vue項目,目錄說明如下
目錄/文件 | 說明 |
---|---|
build | 項目構建(webpack)相關代碼 |
config | 配置目錄,包括端口號等。我們初學可以使用默認的。 |
node_modules | npm 加載的項目依賴模塊 |
src | 這里是我們要開發的目錄,基本上要做的事情都在這個目錄里。里面包含了幾個目錄及文件:assets: 放置一些圖片,如logo等。components: 目錄里面放了一個組件文件,可以不用。App.vue: 項目入口文件,我們也可以直接將組件寫這里,而不使用 components 目錄。main.js: 項目的核心文件。index.css: 樣式文件。 |
static | 靜態資源目錄,如圖片、字體等。 |
public | 公共資源目錄。 |
test | 初始測試目錄,可刪除 |
.xxxx文件 | 這些是一些配置文件,包括語法配置,git配置等。 |
index.html | 首頁入口文件,你可以添加一些 meta 信息或統計代碼啥的。 |
package.json | 項目配置文件。 |
README.md | 項目的說明文檔,markdown 格式 |
dist | 使用 npm run build 命令打包后會生成該目錄。 |
- 利用idea工具來運行vue項目
add/edit configurations -> +號 -> npm -> scripts框框填寫:dev -> apply(應用)
2.4、使用Idea開發vue項目
我們編寫腳本的時候,可能會由於校驗過於嚴格導致各種編譯報錯,這對於新手而言是不太友好,
關閉ESlint校驗方式如下:
- 方式一:
- 修改 build目錄 webpack.base.conf.js 文件,找到 createLintingRule() ,將其刪除或注釋掉,重啟idea即可
- 方式二:(建議使用此法)
- 修改config目錄下的index.js 文件,找到useEslint參數,修改為false
Idea中vue文件eslint校驗 各種紅色波浪線處理:
- settings->搜索eslint,找到Eslint選項選擇它 -> 右側窗口選擇Disable ESlint
介紹 瀏覽器 -> (main.js -> app.vue) -> index.html 流程,然后編寫一個例子
2.5、vue中其他常用模塊
2.5.1、路由
- 安裝
cnpm install vue-router@4
- 使用
2.5.2、axios
- 安裝
cnpm install axios
- 使用