1.MVVM思想
M:Model模型層,包括數據和一些基本操作。
V:Viem視圖層,視圖頁面渲染結果。
VM:Viem-Model,模型與視圖的雙向操作,無需開發人員干涉。
在MVVM之前,開發人員從後端獲取需要的數據模型,然後要通過DOM操作Model渲染到View中。而後當用戶操作視圖,我們還需要通過DOM獲取View中的數據,然後同步到Model中。
MVVM中的VM要做的事情就是把DOM操作完全封裝起來,開發人員不用再關心Model和View之間是如何互相影響的。
MVVM支持雙向綁定,意思就是當M層數據進行修改時,VM層會監測到變化,並且通知V層進行相應的修改,反之修改V層則會通知M層數據進行修改,以此也實現了視圖與模型層的相互解耦;
2.Vue簡介與HelloWord
Vue : 是一套用於構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計爲可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易於上手,還便於與第三方庫或既有項目整合。另一方面,當與現代化的工具鏈以及各種支持類庫結合使用時,Vue 也完全能夠爲複雜的單頁應用提供驅動。
npm init -y //初始化項目
npm install vue //安裝vue
引入vue
<script src="./node_modules/vue/dist/vue.js"></script>
- HelloWord程序
//1、vue聲明式渲染
let vm = new Vue({
el: "#app",//綁定元素
data: { //封裝數據
name: "張三",
num: 1
},
methods:{ //封裝方法
cancle(){
this.num -- ;
},
hello(){
return "1"
}
}
});
//2、雙向綁定,模型變化,視圖變化。反之亦然。
//3、事件處理
//v-xx:指令
//1、創建vue實例,關聯頁面的模板,將自己的數據(data)渲染到關聯的模板,響應式的
//2、指令來簡化對dom的一些操作。
//3、聲明方法來做更復雜的操作。methods裏面可以封裝方法。
- vs安裝插件和瀏覽器插件
谷歌插件下載安裝包解壓後直接在擴展程序中加載已解壓的擴展程序即可
3.vue指令
-
差值表達式
1.格式:{{ }}
只能用在標籤體中
可以直接獲取Vue實例中定義的數據或函數;
該表達式支持js語法,可以使用js內置函數(必須有返回值例如:let a=1+1不能使用差值表達式);
2.差值閃爍:使用{{}}方式在網速較慢時會出現的在數據未加載完成時,頁面會顯示原始的{{value}}加載完才顯示正確數據我們稱爲差值閃爍 -
v-text、v-html指令(單向綁定)
v-text綁定文本 v-html綁定html
使用{{name}} 就是v-text的縮寫
注意:如果標籤沒有text屬性該綁定失效 比如你在一個文本框上使用v-text是沒有效果的
<div id="app">
{{msg}} {{1+1}} {{hello()}}<br/>
<span v-html="msg"></span>
<br/>
<span v-text="msg"></span>
</div>
<script>
new Vue({
el:"#app",
data:{
msg:"<h1>Hello</h1>",
link:"http://www.baidu.com"
},
methods:{
hello(){
return "World"
}
}
})
</script>
- ***v-bind可簡寫爲:(單向綁定)***給html標籤的屬性綁定
<!-- 給html標籤的屬性綁定 -->
<div id="app">
<a v-bind:href="link">gogogo</a>
<!-- vue對class,style進行增強 當isActive爲true時span標籤的calss屬性中才有active,
style的屬性與color1雙向綁定-->
<span v-bind:class="{active:isActive,'text-danger':hasError}"
:style="{color: color1,fontSize: size}">你好</span>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
link: "http://www.baidu.com",
isActive:true,
hasError:true,
color1:'red',
size:'36px'
}
})
</script>
- ***v-model(雙向綁定)***綁定表單項和自定義組件
<!-- 表單項,自定義組件 -->
<div id="app">
精通的語言:
<input type="checkbox" v-model="language" value="Java"> java<br/>
<input type="checkbox" v-model="language" value="PHP"> PHP<br/>
<input type="checkbox" v-model="language" value="Python"> Python<br/>
選中了 {{language.join(",")}}
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
language: []
}
})
</script>
- ***v-on可簡寫爲@***綁定事件
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="num++">點贊</button>
<!--事件指定一個回調函數,必須是Vue實例中定義的函數;v-on可以直接簡寫成@-->
<button @click="cancle">取消</button>
<h1>有{{num}}個贊</h1>
<!-- 事件修飾符 :-->
<div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">
大div
<!-- @click.stop阻止事件冒泡到父元素(當點擊小div時會彈框兩次,使用該修飾符會阻止冒泡,只彈框一次) -->
<div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">
小div <br />
<!-- @click.prevent.stop阻止默認事件發生並調用hello函數 -->
<a href="http://www.baidu.com" @click.prevent.stop="hello">去百度</a>
</div>
</div>
<!-- 按鍵修飾符:v-on:keyup.up="num+=2"每按↑鍵一次num就會加2,
@click.ctrl="num=10"按ctrl鍵num變爲10 -->
<input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />
提示:
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
num: 1
},
methods:{
cancle(){
this.num--;
},
hello(){
alert("點擊了")
}
}
})
</script>
- v-for 遍歷循環
<div id="app">
<ul>
<li v-for="(user,index) in users" :key="user.name" v-if="user.gender == '女'">
<!-- 1、顯示user信息:v-for="item in items" -->
當前索引:{{index}} ==> {{user.name}} ==> {{user.gender}} ==>{{user.age}} <br>
<!-- 2、獲取數組下標:v-for="(item,index) in items" -->
<!-- 3、遍歷對象:
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
-->
對象信息:
<span v-for="(v,k,i) in user">{{k}}=={{v}}=={{i}};</span>
</li>
</ul>
<ul>
<!-- 4、遍歷的時候都加上:key(被遍歷的元素中的唯一標識如user.id)來區分不同數據,提高vue渲染效率
下例使用索引區分, -->
<li v-for="(num,index) in nums" :key="index"></li>
</ul>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
users: [{ name: '柳巖', gender: '女', age: 21 },
{ name: '張三', gender: '男', age: 18 },
{ name: '范冰冰', gender: '女', age: 24 },
{ name: '劉亦菲', gender: '女', age: 18 },
{ name: '古力娜扎', gender: '女', age: 25 }],
nums: [1,2,3,4,4]
},
})
</script>
- v-if和v-show
<!--
v-if,顧名思義,條件判斷。當得到結果爲true時,所在的元素纔會被渲染。
v-show,當得到結果爲true時,所在的元素纔會被顯示,。
-->
<div id="app">
<button v-on:click="show = !show">點我呀</button>
<!-- 1、使用v-if顯示 ,標籤直接消失-->
<h1 v-if="show">if=看到我....</h1>
<!-- 2、使用v-show顯示,本質是改變display屬性爲none隱藏 -->
<h1 v-show="show">show=看到我</h1>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
show: true
}
})
</script>
- v-else和v-else-if
<div id="app">
<button v-on:click="random=Math.random()">點我呀</button>
<span>{{random}}</span>
<h1 v-if="random>=0.75">
看到我啦?! >= 0.75
</h1>
<h1 v-else-if="random>=0.5">
看到我啦?! >= 0.5
</h1>
<h1 v-else-if="random>=0.2">
看到我啦?! >= 0.2
</h1>
<h1 v-else>
看到我啦?! < 0.2
</h1>
</div>
<script>
let app = new Vue({
el: "#app",
data: { random: 1 }
})
</script>
4.計算屬性、偵聽器、過濾器
- 計算屬性和偵聽器
<div id="app">
<ul>
<li>西遊記; 價格:{{xyjPrice}},數量:<input type="number" v-model="xyjNum"> </li>
<li>水滸傳; 價格:{{shzPrice}},數量:<input type="number" v-model="shzNum"> </li>
<li>總價:{{totalPrice}}</li>
{{msg}}
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
xyjPrice: 99.98,
shzPrice: 98.00,
xyjNum: 1,
shzNum: 1,
msg: ""
},
//某些結果是基於之前數據實時計算出來的,
//我們可以利用計算屬性computed來完成,當computed中使用到的任意屬性發生變化都會重新計算。
computed: {
totalPrice(){
return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum
}
},
// watch可以讓我們監控一個值的變化。
//放在 data 中的對象,一旦發生改變就會執行相應的操作,當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。
watch: {
xyjNum(newVal,oldVal){
if(newVal>=3){
this.msg = "庫存超出限制";
this.xyjNum = 3
}else{
this.msg = "";
}
}
},
})
</script>
- 過濾器
<!-- 過濾器常用來處理文本格式化的操作。過濾器可以用在兩個地方:雙花括號插值和 v-bind 表達式 -->
<div id="app">
<ul>
<li v-for="user in userList">
{{user.id}} ==> {{user.name}} ==> {{user.gender == 1?"男":"女"}} ==>
{{user.gender | genderFilter}} ==> {{user.gender | gFilter}}
</li>
</ul>
</div>
<script>
// 全局過濾器:可以在任何vue實例中使用
Vue.filter("gFilter", function (val) {
if (val == 1) {
return "男~~~";
} else {
return "女~~~";
}
})
let vm = new Vue({
el: "#app",
data: {
userList: [
{ id: 1, name: 'jacky', gender: 1 },
{ id: 2, name: 'peter', gender: 0 }
]
},
filters: {
// filters 定義局部過濾器,只可以在當前vue實例中使用(局部的只能在當前Vue實例中使用)
genderFilter(val) {
if (val == 1) {
return "男";
} else {
return "女";
}
}
}
})
</script>
5.組件化
在大型應用開發的時候,頁面可以劃分成很多部分。往往不同的頁面,也會有相同的部分。例如可能會有相同的頭部導航。
但如果每個頁面都獨自開發,是很廢程序員的。多以我們會把頁面的不同部分拆分成獨立的組件,然後再在不同頁面就可以共享這些組件,避免重複開發。
- 一個組件就是一個vue實例.一次它在被定義時也會接受:data、methods、生命週期函數等
- 不同的是組建不會與頁面的元素綁定,否則就無法複用因此沒有el屬性
- 但是組件渲染需要html模板,所以增加了template屬性,值就是HTML模板。
- 全局組件定義完畢,任何vue實例可以直接在HTML中通過組件名稱使用組件
- 組件中data必須是一個函數,不再是一個對象。
<div id="app">
<button v-on:click="count++">我被點擊了 {{count}} 次</button>
<!-- 全局組件引入 -->
<counter></counter>
<!-- 局部組件引入 -->
<button-counter></button-counter>
</div>
<script>
//1、全局聲明註冊一個組件
Vue.component("counter", {
template: `<button v-on:click="count++">我被點擊了 {{count}} 次</button>`,
data() {
return {
count: 1
}
}
});
//2、局部聲明一個組件
const buttonCounter = {
template: `<button v-on:click="count++">我被點擊了 {{count}} 次~~~</button>`,
data() {
return {
count: 1
}
}
};
new Vue({
el: "#app",
data: {
count: 1
},
// 將局部聲明的組件註冊到vue實例中
components: {
'button-counter': buttonCounter
}
})
</script>
6.生命週期
每個 Vue 實例在被創建時都要經過一系列的初始化過程——例如,需要設置數據監聽、編譯模板、將實例掛載到 DOM 並在數據變化時更新 DOM 等。同時在這個過程中也會運行一些叫做生命週期鉤子的函數,這給了用戶在不同階段添加自己的代碼的機會。
- 生命週期圖示
- 下例展示了各個鉤子函數中頁面數據與模板渲染的步驟
<div id="app">
<span id="num">{{num}}</span>
<button @click="num++">贊!</button>
<h2>{{name}},有{{num}}個人點贊</h2>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
name: "張三",
num: 100
},
methods: {
show() {
return this.name;
},
add() {
this.num++;
}
},
beforeCreate() {
console.log("=========beforeCreate=============");
console.log("數據模型未加載:" + this.name, this.num);
console.log("方法未加載:" + this.show());
console.log("html模板未加載:" + document.getElementById("num"));
},
created: function () {
console.log("=========created=============");
console.log("數據模型已加載:" + this.name, this.num);
console.log("方法已加載:" + this.show());
console.log("html模板已加載:" + document.getElementById("num"));
console.log("html模板未渲染:" + document.getElementById("num").innerText);
},
beforeMount() {
console.log("=========beforeMount=============");
console.log("html模板未渲染:" + document.getElementById("num").innerText);
},
mounted() {
console.log("=========mounted=============");
console.log("html模板已渲染:" + document.getElementById("num").innerText);
},
beforeUpdate() {
console.log("=========beforeUpdate=============");
console.log("數據模型已更新:" + this.num);
console.log("html模板未更新:" + document.getElementById("num").innerText);
},
updated() {
console.log("=========updated=============");
console.log("數據模型已更新:" + this.num);
console.log("html模板已更新:" + document.getElementById("num").innerText);
}
});
</script>
7.使用Vue腳手架進行模塊化開發
- 第一個vue項目
1.項目打包工具 -g 代表全局安裝(注關掉cmd的快速編輯模式)
npm install webpack -g
2.全局安裝vue腳手架
npm install -g @vue/cli-init
3.初始化vue項目
vue init webpack appname
使用webpack模板初始化一個appname項目,並進行項目相關設置
初始化項目時錯誤
對應解決方案(進入c盤以管理員身份打開Windows PowerShell)
輸入set-ExecutionPolicy RemoteSigned再輸入Y即可。
4.根據模板初始化的提示運行項目
cd vue-model
npm run dev
5.項目文件結構介紹(我們這裏只關注src裏面的內容)
build文件夾打包工具有關代碼
config配置信息,例如端口號,信息等
node_model 當前項目安裝的所有依賴
src編寫代碼的文件夾
src/main.js項目主程序
static靜態資源文件如圖片字體
index.html首頁內容
package.json npm依賴包配置信息
package-lock.json npm依賴包詳細配置信息
7.整個ElementUI快速開發
1.npm 安裝ElementUI它能更好地和 webpack 打包工具配合使用
npm i element-ui
2.導入ElementUI組件庫(即可使用element提供的各種組件參考官網文檔
)
import ElementUI from ‘element-ui’;
import ‘element-ui/lib/theme-chalk/index.css’;
Vue.use(ElementUI);
3.使用elementUI快速搭建後臺管理系統的頁面
elementUI官網找到Container佈局容器:將實例的代碼複製到src下的App.vue文件中並將組件用標籤包裹
4.vsCode代碼模板的使用
新建全局用戶代碼片段vue.json
給出一個模板實例,將示例複製到新建的代碼片段中
{
"Print to console": {
"prefix": "vue",
"body": [
"<template>",
" <div>",
" </div>",
"</template>",
"",
"<script>",
"export default {",
" // 組件名稱",
" name: 'demo',",
" // 組件參數 接收來自父組件的數據",
" props: {},",
" // 局部註冊的組件",
" components: {},",
" // 組件狀態值",
" data () {",
" return {}",
" },",
" // 計算屬性",
" computed: {},",
" // 偵聽器",
" watch: {},",
" // 組件方法",
" methods: {},",
" // 在實例初始化之後,組件屬性計算之前,如data屬性等",
" beforeCreate () { },",
" // 組件實例創建完成,屬性已綁定,但DOM還未生成,$ el屬性還不存在",
" created () { },",
" // 在掛載開始之前被調用:相關的 render 函數首次被調用。",
" beforeMount () { },",
" // el 被新創建的 vm.$ el 替換,並掛載到實例上去之後調用該鉤子。",
" // 如果 root 實例掛載了一個文檔內元素,當 mounted 被調用時 vm.$ el 也在文檔內。",
" mounted () { },",
" // 數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。",
" // 你可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。",
" beforeUpdate () { },",
" // 由於數據更改導致的虛擬 DOM 重新渲染和打補丁,在這之後會調用該鉤子。",
" // 當這個鉤子被調用時,組件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。",
" updated () { },",
" // keep-alive 組件激活時調用。 僅針對keep-alive 組件有效",
" activated () { },",
" // keep-alive 組件停用時調用。 僅針對keep-alive 組件有效",
" deactivated () { },",
" // 實例銷燬之前調用。在這一步,實例仍然完全可用。",
" beforeDestroy () { },",
" // Vue 實例銷燬後調用。調用後,Vue 實例指示的所有東西都會解綁定,",
" // 所有的事件監聽器會被移除,所有的子實例也會被銷燬。",
" destroyed () { }",
"}",
"</script>",
"",
"<!--使用了scoped屬性之後,父組件的style樣式將不會滲透到子組件中,-->",
"<!--然而子組件的根節點元素會同時被設置了scoped的父css樣式和設置了scoped的子css樣式影響,-->",
"<!--這麼設計的目的是父組件可以對子組件根元素進行佈局。-->",
"<style scoped>",
"",
"</style>",
"$2"
],
"description": "Log output to console"
}
}