前言:" 今生遇汝,何其幸哉;於我蒙昧之時遇到你,於我大霧初透之時愛上你,於我大智初醒之時沉淪你。 "
指令與修飾符
創建實例
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
結果 Hello Vue!
v-html
<div id="box">
<!-- v-html -->
<div v-html="myhtml"></div>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
myhtml: "<b>1111</b>"
}
})
</script>
v-html,防止xSS,csrf (
(1)前端過濾
(2)后台轉義(< > <>)
(3)給cookie加上屬性http
)
v-cloak與v-text
- 使用 v-cloakv-text 與能夠解決插值表達式閃爍的問題
<p v-cloak>{{msg}}</p>
<p v-text="msg"></p>
//=====
<style>
[v-cloak]{
display: none;
}
</style>
v-show 與 v-if
<div id="box">
<div v-show="isShow">動態顯示與隱藏</div>
<div v-if="isCreated">動態創建與刪除</div>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
isShow: false,
isCreated: true
}
})
</script>
vue-class 綁定
<div id="box">
<div :class="isActive?'red':'yellow'">
我的樣式是動態切換的!----三目寫法
</div>
<button @click="handleClick()">click</button>
<div :class="classObj">
我的樣式是動態切換的!----對象寫法
</div>
<div :class="classArr">
我的樣式是動態切換的!----數組寫法
</div>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
isActive: true,
classObj: {
a: true,
b: true
}, // a,b 為class名稱
classArr: ["a","b"]
},
methods: {
handleClick() {
this.isActive = !this.isActive
}
}
})
</script>
vue-style 綁定
<div id="box">
<button @click="handleClick()">click</button>
<div :style="'background:'+isActive?'red':'yellow'">
我的樣式是動態切換的!----三目寫法
</div>
<div :style="styleObj">
我的樣式是動態切換的!----對象寫法
</div>
<div :style="styleArr">
我的樣式是動態切換的!----數組寫法
</div>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
isActive: true,
styleObj: {
backgroundColor: "red"
},
styleArr: ["a","b"] //建議使用數組 shift()刪除所有的樣式
},
methods: {
handleClick() {
this.isActive = !this.isActive
}
}
})
</script>
vue 條件渲染
<div id="box">
<button @click="handleClick()">click</button>
<div v-if="isCreated">動態的創建與刪除----111</div>
<div v-else>動態的創建與刪除----222</div>
<!-- 實例 -->
<ul v-if="dataList.length">
<li v-for="data in dataList">
{{data}}
</li>
</ul>
<div v-else>空空如也</div>
<div v-if="which==1">111</div>
<div v-else-if="which==2">222</div>
<div v-else>333</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
isCreated: true,
dataList: [],
which: 1
},
methods: {
handleClick() {
this.isCreated = !this.isCreated,
this.dataList = ["111", "2222"]
}
}
})
</script>
vue 列表渲染
<div id="box">
<ul>
<li v-for="(data,index) in dataList">
{{data}}----{{index}}
</li>
</ul>
<ul>
<li v-for="(data,index) of dataList">
{{data}}----{{index}}
</li>
</ul>
<ul>
<li v-for="(data,key) in dataObj">
{{data}}----{{key}}
</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
dataList: ["111", "2222", "333"],
dataObj: {
name: "qiandu",
age: 18,
sex: "男"
}
}
})
</script>
vue 列表key值設置
跟蹤每個節點的身份,從而重用和重新排序現有元素
理想的 key值是每項都有的且唯一的id。data.id
列表數組檢測
a.使用以下方法操作數組,可以檢測變動
push() pop() shift() unshift() splice() sort() reverse()
b. filter(), concat() 和 slice() ,map(),新數組替換舊數組
c.不能檢測以下變動的數組
-
vm.items [ indexOfltem] = newValue
-
解決 (1) Vue.set(example1.items, indexOfltem, newValue)
(2)splice
過濾--模糊查詢
<div id="box">
<input type="text" @input="handleInput()" v-model="mytext" />
<!-- @change 只要失去焦點就會觸發 -->
<ul>
<li v-for="data in dataList">
{{data}}
</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
mytext: '',
dataList: ["111", "2222", "333"],
},
methods: {
handleInput() {
// console.log("只要value改變 就會觸發");
//利用輸入框的字符,過濾包含字段的元素
//filter 過濾
var newList = this.dataList.filter(item => item.indexOf(this.mytext) > -1);
console.log(newList);
/* 改變列表值 有兩種方法
1. 復制一份數組 List: ["111", "2222", "333"]
var newList = this.List.filter(item => item.indexOf(this.mytext) > -1);
this.dataList = newList;
2. 計算屬性 后期使用
*/
}
}
})
</script>
事件處理器
<div id="box">
<!-- 無需參數 -->
<button @click="handleClick()">click1</button>
<!-- 需要參數 -->
<button @click="handleClick">click2</button>
<!-- 語句簡單 盡量避免 -->
<button @click="isCreated = !isCreated">click3</button>
<div v-show="isCreated">動態的創建與刪除----111</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
isCreated: false,
},
methods: {
handleClick() {
this.isCreated = !this.isCreated;
}
}
})
</script>
事件修飾符
<div id="box">
<!-- 點自己才會觸發 -->
<ul @click.self="handleULClick">
<li @click.stop="handleLiClick"> 111</li>
<li @click.once="handleLiClick"> 222</li>
<li @click="handleLiClick"> 111</li>
</ul>
<a href="www.baidu.com" @click.prevent="handleChangePage">changePage</a>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
isCreated: false,
},
methods: {
// handleClick() {
// this.isCreated = !this.isCreated;
// }
handleLiClick(ev) {
// ev.stopPropagation(); 原生
console.log("111");
},
handleULClick() {
console.log("222");
},
handleChangePage(ev) {
// ev.preventDefault(); 阻止默認
console.log("333")
}
}
})
</script>
按鍵修飾符
<div id="box">
<a href="www.baidu.com" @click.prevent="handleChangePage">changePage</a>
<!-- 鍵值也可以 -->
<input type="text" @keyup.enter="handleULClick($event)" />
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
},
methods: {
handleULClick() {
console.log("222");
//傳統方法
// if (ev.keyCode === 13) {
// //....13表示回車鍵
// }
},
}
})
</script>
表單控件綁定
<div id="box">
<input type="text" v-model="mytext">
<textarea name="" id="" cols="30" rows="10" v-model="mytext"></textarea>
{{mytext}}
<br>
<input type="checkbox" v-model="isChecked">記住我
<br>
<p>你喜歡的運動為:
<input type="checkbox" v-model="checkgroup" value="游泳" />游泳
<input type="checkbox" v-model="checkgroup" value="滑冰" />滑冰
</p>
{{checkgroup}}
<br>
<p>你最喜歡的運動為:
<input type="radio" v-model="picked" value="游泳" />游泳
<input type="radio" v-model="picked" value="滑冰" />滑冰
</p>
{{picked}}
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
mytext: "aaaa",
isChecked: true,
checkgroup: [],
picked: ""
}
})
</script>
購物車案例
<div id="box">
<input type="checkbox" @change="handleChange" v-model="isAllChecked">
<ul>
<li v-for="data in dataList">
<input type="checkbox" v-model="checkGroup" :value="data" @change="handleLiChange">
{{data}}
<button @click="data.number++">add</button>
{{data.number}}
<button @click="handleDelClick(data)">del</button>
</li>
</ul>
{{checkGroup}}
<p>總金額為:{{getSum()}}</p>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
checkGroup: [],
isAllChecked: false,
dataList: [
{
name: "商品1",
price: 10,
number: 1,
id: "1"
},
{
name: "商品2",
price: 20,
number: 4,
id: "2"
}
]
},
methods: {
getSum() {
//函數計算的狀態改變,會自動執行一次
var sum = 0;
for (var i in this.checkGroup) {
sum += this.checkGroup[i].number * this.checkGroup[i].price;
}
return sum;
},
handleChange() {
if (this.isAllChecked) {
this.checkGroup = this.dataList;
} else {
this.checkGroup = [];
}
},
handleLiChange() {
if (this.dataList.length === this.checkGroup.length) {
this.isAllChecked = true;
} else {
this.isAllChecked = false;
}
},
handleDelClick(data) {
if (data.number != 0) {
data.number--
} else { data.number = 0 }
}
}
})
</script>
表單修飾符
<!-- 失去焦點才顯示 -->
<input type="text" v-model.lazy="mytext">
<!-- 只能輸入數字 效果不好 -->
<input type="text" v-model.number="mynumber">
<!-- 去除收尾空格 -->
<input type="text" v-model.trim="myname">
axios
- 方式一
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
aaa: function () {
axios.get("xxx").then((res) => {
console.log(res.data)
}).catch((err) => {
});
},
bbb: function () {
axios.post("xxx", {
//請求參數
}).then(res => {
console.log(res.data)
}).catch(err => {
console.log(err)
})
}
- 方式二
- 安裝axios依賴
npm install axios
- 在main.js中引入
import axios from 'axios'
Vue.prototype.$axios = axios;
- 使用
mounted() {
this.$axios.get('http://www.liulongbin.top:3005/api/getlunbo')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
vue引入Axios
使用增刪改查
Vue項目引入Axios 插件(封裝):
- 完整寫法
axios({
url:"",
headers:{
}
}).then(res=>{
console.log(res.data)
}).catch(err => {
console.log(err)
})
計算屬性
- 定義像函數 使用像屬性
- 計算屬性會緩存
計算屬性模糊查詢
<div id="box">
<input type="text" v-model="mytext" />
<!-- @change 只要失去焦點就會觸發 -->
<ul>
<li v-for="data in getDataList">
{{data}}
</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#box",
data: {
mytext: '',
dataList: ["111", "2222", "333"],
},
computed: {
getDataList() {
return this.dataList.filter(item => item.indexOf(this.mytext) > -1)
}
}
})
</script>
組件化開發
定義全局組件
<div id="box">
<navbar></navbar>
</div>
<script type="text/javascript">
//1.全局定義組件(作用域隔離)
Vue.component("navbar", {
template: `
<div @click="handleback()" style="background:red">
我是導航欄
</div>
`,
methods: {
handleback() {
console.log("back...")
}
}
})
new Vue({
el: "#box",
})
</script>
局部
<div id="box">
<navbar></navbar>
</div>
<script type="text/javascript">
//1.全局定義組件(作用域隔離)
Vue.component("navbar", {
template: `
<div @click="handleback()" style="background:red">
我是導航欄
<child></child>
<navbarchild></navbarchild>
</div>
`,
methods: {
handleback() {
console.log("back...")
}
},
components: {
navbarchild: {
template: `
<div >
我是child組件----局部定義
</div>
`
}
} //局部
})
//全局
Vue.component("child", {
template: `
<div style="background:green">
我是child組件----全局定義
</div>
`,
methods: {
handleback() {
console.log("back...")
}
}
})
new Vue({
el: "#box",
})
</script>
父傳子與屬性驗證
<div id="box">
<navbar myname="home" :myshow="false"></navbar>
<navbar myname="list" :myshow="true"></navbar>
<navbar :myname="parentname" :myshow="true"></navbar>
</div>
<script type="text/javascript">
//全局
Vue.component("navbar", {
template: `
<div style="background:green">
<button v-show="myshow">返回</button>
導航欄----{{myname}}
<button v-show="myshow">首頁</button>
</div>
`,
// props: ["myname","myshow"] //接收父組件傳來的屬性 js代碼用v-bind
//屬性驗證
props:{
myname:String,
myshow:Boolean
}
})
new Vue({
el: "#box",
data: {
parentname: "parentname屬性"
}
})
</script>
子傳父
<div id="box">
<navbar @myevent="handleEvent($event)"></navbar>
<!-- 或者 -->
<navbar @myevent="handleEvent"></navbar>
</div>
<script type="text/javascript">
//全局
Vue.component("navbar", {
template: `
<div style="background:green">
<button @click="pay()">返回</button>
</div>
`,
data() {
return {
txt: "子組件的內容"
}
},
methods: {
pay() {
this.$emit("myevent",this.txt) //分發事件
}
}
})
new Vue({
el: "#box",
data: {
parentname: "parentname屬性"
},
methods: {
handleEvent() {
console.log("父組件收到!")
}
}
})
</script>
- 案例 側邊欄的隱藏與顯示
<div id="box">
<!-- 2.觸發后 執行父組件方法 -->
<navbar @myevent="handleEvent($event)"></navbar>
<sidebar v-show="isShow"></sidebar>
</div>
<script type="text/javascript">
Vue.component("navbar", {
template: `<div>
<button @click="handleClick">點擊</button>
</div>
`,
methods: {
handleClick() {
this.$emit("myevent") //1.點擊按鈕 觸發回調函數 找到 myevent
}
}
})
Vue.component("sidebar", {
template: `
<div>
<ul>
<li>
選項1
</li>
<li>
選項2
</li>
</ul>
</div>`
})
new Vue({
el: "#box",
data: {
isShow: false
},
methods: {
handleEvent() {
this.isShow = !this.isShow //3. 控制
}
}
})
</script>
- 方法改造
<div id="box">
<!-- 2.觸發后 執行父組件方法 -->
<navbar>
<button @click="handleEvent($event)">點擊</button>
</navbar>
<sidebar v-show="isShow"></sidebar>
</div>
<script type="text/javascript">
Vue.component("navbar", {
template: `<div>
<slot></slot>
</div>
})
Vue.component("sidebar", {
template: `
<div>
<ul>
<li>
選項1
</li>
</div>`
})
new Vue({
el: "#box",
data: {
isShow: false
},
methods: {
handleEvent() {
this.isShow = !this.isShow //3. 控制
}
}
})
</script>
父傳子靠屬性,子傳父靠事件**
ref-父子通信通信
<div id="box">
<input type="text" ref="mytext">
<button @click="handleEvent()">click</button>
<child ref="mychild"></child>
</div>
<script type="text/javascript">
Vue.component("child", {
template: `
<div>
child
</div>
`,
data() {
return {
name: "childName"
}
},
methods: {
aa(data) {
console.log("自己的", data)
}
}
})
new Vue({
el: "#box",
methods: {
handleEvent() {
console.log(this.$refs.mytext.value)
console.log(this.$refs.mychild)
this.$refs.mychild.aa("傳過去的")
}
}
})
/*
絕對的控制權
1. ref放在標簽上拿到的是原生節點
2. ref放在組件上,拿到的是組件對象
*/
</script>
非父子通信--事件總線
<div id="box">
<author></author>
<user></user>
</div>
<script type="text/javascript">
/* 創建事件總線 $emit與$on */
//創建空的vue實例賦值給一個變量
var bus = new Vue();
Vue.component("author", {
template: `
<div>
<input type="text" ref="mytext" />
<button @click="handleClick()">發布</button>
</div>
`,
methods: {
handleClick() {
bus.$emit("mseeage",this.$refs.mytext.value)
}
}
})
Vue.component("user", {
//合適的位置訂閱=>當前組件創建完成時 bus.$on
template: `
<div>
我是用戶
</div>
`,
mounted() { //組件創建完調用
bus.$on("mseeage", (data) => {
console.log("收到推送",data)
})
console.log("生命周期函數--當前組件dom創建完成之后就會調用")
}
})
</script>
動態組件
<div id="box">
<!-- vue 提供動態組件 is屬性 -->
<component is="home"></component>
<!-- 避免重新渲染 -->
<keep-alive>
<component is="home"></component>
</keep-alive>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
components: {
"home": {
template: `<div>home組件</div>`
},
"list": {
template: `<div>list組件</div>`
},
"footer": {
template: `<div>footer組件</div>`
}
}
})
</script>
slot插槽
- 使用場景:輪播圖
<div id="box">
<swiper>
<li v-for="data in dataList">
{{data}}
</li>
</swiper>
</div>
<script type="text/javascript">
Vue.component("swiper", {
template: `
<div>
<ul>
<slot></slot>
</ul>
</div>
`
})
new Vue({
el: "#box",
data: {
dataList: ["1111", "222", "333"]
}
})
</script>
- 具名插槽 [ name 與 slot ]
<div id="box">
<swiper>
<p slot="a">111</p>
<p slot="b">222</p>
</swiper>
</div>
//=============================
Vue.component("swiper", {
template: `
<div>
<slot name="a"></slot>
---------------------
<slot name="b"></slot>
</div>
`
})
元素過度
不在詳細學習 具體請看教程
- 引入animate 動畫庫
- 在線演示地址:===> animate.css動畫演示_dowebok
<link href="https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css" rel="stylesheet">
//或者
npm install animate.css
// or
yarn install animate.css
使用詳解===> Vue.animate.css組件庫的使用的詳細解析
生命周期
- mounted:頁面一創建發送ajax請求
- dom節點更新完之后的操作放入updated之中
過濾器
<!-- 格式:要有空格 -->
<img src="xxx.jpg | aaafilter" alt="">
<!-- js -->
//過濾器
Vue.filter("aafilter", function (data) {
return data.replce("xxx", "xxxx"); //替換源---替換目標
})
Swiper輪播
- 引入cdn
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css">
<script src="https://unpkg.com/swiper/swiper-bundle.js"> </script>
- 實例
<div id="box">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="data in dataList" style="width: 300px;height: 300px;">
{{data}}
</div>
</div>
<!-- 如果需要分頁器 -->
<div class="swiper-pagination"></div>
<!-- 如果需要導航按鈕 -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- 如果需要滾動條 -->
<div class="swiper-scrollbar"></div>
</div>
</div>
<script type="text/javascript">
new Vue({
el: "#box",
data: {
dataList: []
},
mounted() { //swiper放入mounted會出現初始化過早問題
setTimeout(() => {
this.dataList = ["1111", "2222", "3333"] //異步更新dom節點
}, 2000)
},
updated() {
new Swiper('.swiper-container', {
// direction: 'vertical', // 垂直切換選項
loop: true, // 循環模式選項
// 如果需要分頁器
pagination: {
el: '.swiper-pagination',
clickable: true
},
// 如果需要前進后退按鈕
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// 如果需要滾動條
scrollbar: {
el: '.swiper-scrollbar',
},
//設置自動輪播
autoplay: true
})
}
})
</script>
上述方法使用太麻煩,我們封裝成組件
<!-- css 自己設置 -->
<swiper :key="dataList.length">
<div class="swiper-slide" v-for="data in dataList" style="width: 300px;height: 300px;">
{{data}}
</div>
</swiper>
//===================================
Vue.component("swiper", {
template: `
<div class="swiper-container">
<div class="swiper-wrapper">
<slot></slot>
</div>
<!-- 如果需要分頁器 -->
<div class="swiper-pagination"></div>
<!-- 如果需要導航按鈕 -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- 如果需要滾動條 -->
<div class="swiper-scrollbar"></div>
</div>
`,
mounted() {
new Swiper('.swiper-container', {
// direction: 'vertical', // 垂直切換選項
loop: true, // 循環模式選項
// 如果需要分頁器
pagination: {
el: '.swiper-pagination',
clickable: true
},
// 如果需要前進后退按鈕
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// 如果需要滾動條
scrollbar: {
el: '.swiper-scrollbar',
},
//設置自動輪播
autoplay: true
})
}
})
- 用指令封裝
<div id="box">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="(data,index) in dataList" style="width: 300px;height: 300px;" v-swiper=" {
index:index,
length:dataList.length
}">
{{data}}
</div>
</div>
<!-- 如果需要分頁器 -->
<div class="swiper-pagination"></div>
<!-- 如果需要導航按鈕 -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</div>
<script type="text/javascript">
Vue.directive("swiper", {
inserted(el, bind) {
if (bind.value.index === bind.value.length - 1) {
new Swiper('.swiper-container', {
// direction: 'vertical', // 垂直切換選項
loop: true, // 循環模式選項
// 如果需要分頁器
pagination: {
el: '.swiper-pagination',
clickable: true
},
// 如果需要前進后退按鈕
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// 如果需要滾動條
scrollbar: {
el: '.swiper-scrollbar',
},
})
}
}
})
new Vue({
el: "#box",
data: {
dataList: []
},
mounted() {
setTimeout(() => {
this.dataList = ["1111", "2222", "3333"]
}, 2000)
}
})
</script>
指令用法
- 自定義指令 自己可以操作 Dom
<div id="box">
<div v-qiandu="'red'">1111</div>
<div v-qiandu="color">1111</div>
</div>
<script type="text/javascript">
Vue.directive("qiandu", {
inserted(el, bind) { //el:獲取dom
//插入指令 ----創建階段 只執行一次
console.log("當前節點插入到父節點中了")
console.log(el)
console.log(bind)
el.style.background=bind.value //改變背景色
},
update(el, bind) {
el.style.background=bind.value
}
})
new Vue({
el: "#box",
data: {
color:"yellow"
},
computed: {
}
})
</script>
腳手架
cli配置
安裝Node.js
配置 ===> 安裝npm及cnpm(Windows) - 山高我為峰 - 博客園 (cnblogs.com)
Vue cli安裝
npm install -g @vue/cli
# OR
yarn global add @vue/cli
創建腳手架
- 創建路徑運行終端 輸入
vue create xxx
- 一系列設置
具體配置教程: 腳手架配置
- 所有的靜態資源全部放入public文件夾下 引入到
index.html
中
<link rel="stylesheet" href="<%= BASE_URL %>public下的文件路徑">
- 模塊化引入css
import 'swiper/dist/css/swiper.css'
單文件組件
- 以xxx.vue命名
- 結構樣式
基本寫法
<template>
</template>
<script>
export default {
};
</script>
<style>
</style>
例子
//Navbar.vue
<template>
<nav>導航欄</nav>
</template>
//APP.vue
<template>
<div id="app">
<!-- <img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/> -->
<p>HelloWorld</p>
<Navbar></Navbar>
<siderbar></siderbar>
</div>
</template>
<script>
import Navbar from "./components/Navbar.vue";
import Siderbar from "./components/Siderbar.vue";
// import Vue from "vue";
// Vue.component("Navbar", NavBar);
// Vue.component("Siderbar", Siderbar);
export default {
name: "App",
components: {
Navbar:Navbar,
Siderbar:Siderbar,
},
};
</script>
注意!!!
為防止互相影響 加上 scoped
屬性
打包
修復錯誤
npm run lint
上線項目
npm run build
成功生成dist文件夾拷出里面文件即可
跨域請求
解決跨域請求
在 vue.config.js
配置(與 package.json )同級
注意:更改配置文件要重啟服務器
module.exports = {
devServer: {
proxy: {
'/api': { // *: 所有請求都會轉到target
target: '<url>',
// ws: true,
changeOrigin: true
},
'/api': { // 第二個
target: '<url>',
// ws: true,
changeOrigin: true
},
// '/foo': {
// target: '<other_url>'
// }
}
}
}
//比如 http:www.baidu.com/ajax?&q=ewqe
// api填寫:ajax
//target填:http:www.baidu.com
//axios填寫后面字段:/ajax?&q=ewqe
路由
- 寫法
路由配置
- 路徑改變,頁面不會刷新
相關配置教程 vue的路由安裝及配置
關於components與views文件夾
- 把需要共享的組件放入到 components 文件夾中
- 把單頁面或者只用於一次的組件放入到 views 之中
- 引入路由 新建
vouter.js
與main.js
同級
npm install vue-router
- 編寫路由
import Vue from 'vue' // 引入vue
import VRouter from 'vue-router' // 引入路由
import File from '@/views/File' // 引入需要用到路由的頁面 @:表示指向src文件夾
import Center from '@/views/Center'
Vue.use(VRouter) // vue使用路由
export default new VRouter({ // 創建路由
mode: 'history', // 去掉鏈接中的# /File || /#/File
routes: [ // 此處寫路由 放入數組
{
path: '/File', // 鏈接中的顯示路勁
name: 'File', // 名字
component: File // 引入的路由名稱,必須與import里的名稱一樣
}
]
})
main.js
引入
import router from './router'
Vue.config.productionTip = false
new Vue({
router: router, //key與value相同時,可以簡寫為router
render: h => h(App),
}).$mount('#app')
- 使用
<template>
<div id="app">
<!-- <img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/> -->
<p>HelloWorld</p>
<Navbar></Navbar>
<siderbar></siderbar>
<!-- 路由容器 -->
<router-view></router-view>
</div>
</template>
- 在 ```views文件夾下編寫相應的vue文件``
聲明式導航
- (點擊)事件跳轉到相應路由
router-link 可以達到高亮顯示效果----同步變化
- to :/url
- tag:標簽
- active-class:class
<template>
<div>
<ul>
<!-- 聲明式導航 -->
<router-link to="/File" tag="li" active-class="myactive"
>file</router-link>
<router-link to="/Center" tag="li" active-class="myactive"
>center</router-link
>
<!-- 作用與下方相同 -->
<!-- <li>
<a href="/File">-File-</a>
</li>
<li>
<a href="/Center">-Center-</a>
</li> -->
</ul>
</div>
</template>
<style scoped>
.myactive {
color: red;
}
</style>
重定向
默認顯示或者請求url錯誤顯示
import Vue from 'vue' // 引入vue
import VRouter from 'vue-router' // 引入路由
Vue.use(VRouter) // vue使用路由
export default new VRouter({ // 創建路由
mode: 'history', // 去掉鏈接中的# /File || /#/File
routes: [ // 此處寫路由 放入數組
{
path:'*',
redirect:'/File'
}
]
})
二級路由
- 例子
http://localhost:8080/#/File/aaa
http://localhost:8080/#/File/bbb
router.js
import Vue from 'vue' // 引入vue
import VRouter from 'vue-router' // 引入路由
Vue.use(VRouter) // vue使用路由
export default new VRouter({ // 創建路由
// mode: 'history', // 去掉鏈接中的# /File || /#/File
routes: [ // 此處寫路由 放入數組
{
path: '/File', // 鏈接中的顯示路勁
name: 'File', // 名字
component: File,
children:[ //二級路由數組
{
path:'', //此路徑無需加不能加 /
component:File
}
]
}
]
})
- 父組件留插槽
<!-- 路由容器 -->
<router-view></router-view>
- 創建相應的子組件 並有完整的項目結構
二級放入一級文件夾下
設置子路由默認路徑
import Vue from 'vue' // 引入vue
import VRouter from 'vue-router' // 引入路由
import File from '@/views/File' // 引入需要用到路由的頁面 @:表示指向src文件夾
import Center from '@/views/Center'
Vue.use(VRouter) // vue使用路由
export default new VRouter({ // 創建路由
// mode: 'history', // 去掉鏈接中的# /File || /#/File
routes: [ // 此處寫路由 放入數組
{
path: '/File', // 鏈接中的顯示路勁
name: 'File', // 名字
component: File,
children: [ //二級路由數組
{
path: '',
component: File
},
{
prth: '',
redirect: "/父路徑/子路徑"
}
]
}
]
})
動態路由
點擊事件 列表跳轉詳情頁面
列表頁面
<template>
<div>
<ul>
<li v-for="data in dataList" :key="data" @click="handlePage(data)">
{{ data }}
</li>
</ul>
</div>
</template>
<script>
export default {
setup() {},
data() {
return { dataList: ["1111", "2222", "3333"] };
},
methods: {
handlePage(id) {
console.log(id);
//編程式導航 按照路徑
this.$router.push('/detail/'+id) //跳轉具體頁面
//編程式導航 按照name
this.$router.push({name:"qddetail",params:{id:id}});
},
},
};
</script>
詳情頁面
<template>
<div>detail</div>
</template>
<script>
export default {
setup() { },
mounted() {
// $route,this 獲取參數
console.log(this.$route,this.$route.params.id);
},
};
</script>
動態路由設置
import Vue from 'vue' // 引入vue
import VRouter from 'vue-router' // 引入路由
import File from '@/views/File' // 引入需要用到路由的頁面 @:表示指向src文件夾
import Center from '@/views/Center'
import Erji from '@/views/Erji'
import detail from '@/views/detail'
Vue.use(VRouter) // vue使用路由
export default new VRouter({
// mode: 'history', // 去掉鏈接中的# /File || /#/File
routes: [
{
path: '/detail/:id', // 動態路由 冒號+自定義參數
name: "qddetail",
component: detail
}
]
})
===
//頁面跳轉
this.$router.push('/detail/'+id) //跳轉具體頁面
//存到本地
localStorage.setItem("key","value")
//獲取本地值
localStorage.getItem("key")
//移除 清除
remove clear
History模式
正常的路由采用的是hash模式 url會有#標志 去除#號 只需加上這一句
mode: 'history',
不過這種模式要玩好,還需要后台配置支持。因為我們的應用是個單頁客戶端應用,如果后台沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite .com/user/id
就會返回404,這就不好看了。
路由攔截
- 舉例
我們在選購商品准備付款時,判斷你是否登錄,未登錄跳轉到登錄頁面,
只有登錄后才能購買
-
官網====> 導航守衛 | Vue Router (vuejs.org)
-
分類:
- 全局守衛 :任何一個路由都進行攔截
- 局部守衛:某一個或者多個進行攔截
全局
//驗證方法
const auth = {
isLogin() {
//判斷token session cookie等
return false;
}
}
//全局守衛:任何一個路由跳轉進來執行此方法
VRouter.beforeEach((to, from, next) => {
if (to.path === '/shoppPage') {
if (auth.isLogin()) {
next()
}
} else {
next() //放行
}
})
局部 ===> 寫在組件< script>中
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`
}
}
Vuex
入門
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。尤其為非父子通信服務非常好
- 引入
npm install vuex --save
- 與
main.js
同級新建store.js
內部結構
import Vue from "vue";
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
})
- 在
main.js
中引入
import store from './store'
new Vue({
router: router, //key與value相同時,可以簡寫為router
store,
render: h => h(App),
}).$mount('#app')
- 使用
v-show="this.$store.state.isTabbarShow" //this可以省略
this.$store.state.字段
設計原則
-
應用層級的狀態應該集中到單個store對象中。
-
提交mutation是更改狀態的唯一方法,並且這個過程是同步的。
-
異步邏輯都應該封裝到action里面。
狀態管理
我們需要一個監控或者管理系統來具體了解什么時候改變了狀態
所有修改狀態都會經過 mutations
這一層 調式工具會記錄下來
- 具體更改方法中
this.$store.commit( "自定義函數名",false); //第一個參數就是mutation名字
this.$store.commit( "自定義函數名",true);
store.js
state: {
//放入全局的自定義共享狀態
isTabbarShow: false
},
mutations: { //唯一修改狀態的位置
zidingyi(state, data) {
state.isTabbarShow = data
}
},
異步處理
- 需求
電影網站分為熱映與即將上映 當我們點擊熱映時 ,判斷熱映頁面是否有數據 如果沒有,發起ajax請求 然后存放到mutation 然后頁面更新 如果有 直接取數據 渲染頁面 無需Ajax請求
實現
- 具體地址調用
if (this.$store.state.dataList.length === 0) {
//發送Ajax請求
this.$store.disapath("自定義函數");
} else {
//使用緩存的數據
}
store.js
export default new Vuex.Store({
state: {
//放入全局的自定義共享狀態
dataList: []
},
mutations: { //唯一修改狀態的位置
dataListMutation(state, data) {
state.dataList = data
}
},
actions: { //從后端異步請求需要經過actions
//異步處理
zidingyi(store) {
//axios請求
//引入axios
//傳入到mutations中
store.commit("dataListMutation", "獲取的數據")
}
}
})
寫法轉換
- 對比
this.$store.state.data
import {mapState} from 'vuex'
computed:{
mapState(["data"]) //不建議
...mapState(["data"]) //建議這樣寫 ES6中展開合並運算符
}
導入導出規范
- 問題
很多時候我們只需要某個包中的一個或者幾個方法 但是之前的方法會默認導入全部 加載會慢
- 對比
Bad
//===========A1.js================
function A(){ }
function B(){ }
function C(){ }
//ES6導出規范
const All = {
A,B,C
}
export default All
//=============導入=================
import All from 'A1'
//結果 引入全部方法
Good
//===========A1.js================
export function A(){ }
export function B(){ }
export function C(){ }
//=============導入=================
import {A,B} from 'A1'
//結果 引入A B方法
import {A as myA} from 'A1' //起別名
Gitters
有時候我們需要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。
store.js
getters: { //處理數據
zidingyi(state) {
return state.dataList.filter((item, index) => index < 3)
}
}
- 使用
this.$store.getters.自定義函數名
mapGitters([" "])
mutation常量風格
- 問題
當我們方法多了或者多人開發勢必會出現同名方法 這里可以規避這個問題
- 新建文件夾 比如
type
下的a1.js
有如下代碼
export const SHOW_TABBAR_MUTATION = "show"
store.js
//===先引入a1.js
mutations: { //唯一修改狀態的位置
show (state, data) {
}
//等同於
[SHOW_TABBAR_MUTATION] (state, data) {
}
},
注意:commit 調用方法也需要改
element UI
介紹
Element,一套為開發者、設計師和產品經理准備的基於 Vue 2.0 的桌面端組件庫
-
官網地址 ===> 組件 | Element
element-ui是由餓了么前端團隊推出的一套為開發者、設計師和產品經理准備的基於Vue.js 2.0的桌面組件庫。
擴展使用文章:===> Element-ui 基本使用 - 簡書 (jianshu.com)
安裝
引入element ui到vue中
npm i element-ui -S
<!-- 引入樣式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入組件庫 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
vscoe代碼提示插件 : Element-UI-Snippets
使用方法====> ( Element-UI-Snippets-VSCode插件代碼提示快捷鍵_
引入
- 全局引入,在vue入口
main.js
中增加內容如下
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
- 局部引入,在指定的vue文件中引入所需要的組件或主題樣式,如下
import '@/style/theme/element-variables.scss'
import { Message, MessageBox, Loading } from 'element-ui'
Vue.use(Loading.directive)
Vue.prototype.$loading = Loading.service
Vue.prototype.$msgbox = MessageBox
Vue.prototype.$alert = MessageBox.alert
Vue.prototype.$confirm = MessageBox.confirm
Vue.prototype.$prompt = MessageBox.prompt
Vue.prototype.$message = Message
具體使用請前往官網查看
手勢事件
- 安裝
npm install vue-touch@next --save
- 在 需要的文件中引入
import Vue from "vue";
import VueTouch from 'vue-touch'
Vue.use(VueTouch, {name: 'v-touch'}) v-touch可以是自定義名稱
- 使用
<v-touch @swipeleft="onSwipeLeft">
<div style="background :red;height : 100px">center</div>
</v-touch>
<v-touch
(1)替換標簽
tag="要變成的標簽名稱,默認為div"
(2)定義手勢
@事件類型='回調'
(3)配置手勢事件選項
:小寫事件類型名稱-options="{ direction: 'horizontal', threshold: 100 }
threshold臨界值
directions方向: 'up', 'down', 'left', 'right', 'horizontal', 'vertical', 'all'
具體配置查看hammerjs
(4)阻止/觸發手勢
:enabled="true/false" 允許/禁止所有的手勢
:enabled="{ pinch: true, rotate: false }" 允許和禁止指定手勢
(5)公共組件方法
1、通過ref獲取到該標簽
2、在方法中
this.$refs.tapper.disable('tap')
公共方法:
disable('手勢名稱')
enable('手勢名稱')
toggle('手勢名稱')
disableAll() disable all Recognizers
enableAll() enable all Recognizers
isEnabled('手勢名稱')
(6)自定義手勢
在main.js中,在Vue.use之前使用
VueTouchVueTouch.registerCustomEvent('doubletap', {
type: '手勢名稱',
...手勢事件的配置選項,見(3)
taps: 2 對應tap手勢的觸發點擊次數配置
})
> ...</v-touch>
4、事件類型:
Pan平移
pan, panstart, panmove, panend, pancancel,
panleft, panright, panup, pandown
Pinch縮放
pinch, pinchstart, pinchmove,pinchend,
pinchcancel, pinchin, pinchout
Press按壓
press, pressup
Rotate旋轉
rotate, rotatestart, rotatemove,
rotateend, rotatecancel,
Swipe滑動
swipe, swipeleft, swiperight,
swipeup, swipedown
Tap點擊
tap
Vue SSR
介紹
- 什么是服務器端渲染 (SSR)?
Vue.js 是構建客戶端應用程序的框架。默認情況下,可以在瀏覽器中輸出 Vue 組件,進行生成 DOM 和操作 DOM。然而,也可以將同一個組件渲染為服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最后將這些靜態標記"激活"為客戶端上完全可交互的應用程序。
服務器渲染的 Vue.js 應用程序也可以被認為是"同構"或"通用",因為應用程序的大部分代碼都可以在服務器和客戶端上運行。
優點
-
SEO和爬蟲都是根據url返回的數據來進行的 , 爬蟲seo獲取的數據,是一個沒有數據的殼子
-
首屏渲染 像vue這樣的單頁面應用,首屏渲染是單頁面spa的通病,打包出來的dist過大,會導致首屏加載緩慢
缺點
- 需要配置兩個入口文件,一個是服務端首屏渲染所需要的,第二個是前端激活所需要的
- 相比於單純的spa,服務端渲染加重了服務器的負擔
- 前后端同構,在后端就需要寫前端vue的代碼,與前后端分離相違背,這個可以通過webpack打包實現,只需要配置入口文件以及相應的邏輯就可以。
- 緩存和運維的問題。
服務端與客戶端渲染的對比====> 關於SSR( 服務端渲染 )其利與弊是什么? - 知乎 (zhihu.com)
快速使用
- 安裝
npm install vue vue-server-renderer --save
- 渲染示例
// 第 1 步:創建一個 Vue 實例
const Vue = require('vue')
const app = new Vue({
template: `<div>Hello World ----{{myname}}----{{age}} </div>`,
data:{
myname:"前度",
age:"18"
}
})
// 第 2 步:創建一個 renderer
const renderer = require('vue-server-renderer').createRenderer()
// 在 2.5.0+,如果沒有傳入回調函數,則會返回 Promise:
renderer.renderToString(app).then(html => {
console.log(html)
}).catch(err => {
console.error(err)
})
- 終端調用
node 路徑+文件名
與服務器集成
npm install express --save
const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>訪問的 URL 是: {{ url }}</div>`
})
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.writeHead(200,{"Content-Type":"text/html;charset=utf8"})
res.end(`
<!DOCTYPE html>
<html lang="en">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`)
})
})
server.listen(8080)
node 文件名
訪問端口號
Nuxt.js
- 項目的構建
- 相關教程
ps:此文章只是對Vue2.0的簡單使用與介紹,不涉及更深層面,僅僅入門,有些介紹也引入了其他小伙伴的博客,還望海涵