前言:整合了以前的筆記,加入新記的筆記信息
javascript
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>test</title> </head> <body> <div id="app"> <ul> <li>{{message}}</li> </ul> <input type="text" v-model="message" />{{message}} </div> <script src="../../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "hello world" } }); </script> </body> </html>
v-model.lazycss
只有在input失去焦點的時候纔會刷新數據html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../../js/vue.js"></script> </head> <body> <div id="app"> <ul> <li>{{message}}</li> </ul> <!-- 失去焦點或者enter纔會更新值--> <input type="text" v-model.lazy="message">{{message}} </div> <script> const app = new Vue({ el: "#app", data: { message: "hello world" } }); </script> </body> </html>
order | 語法糖 | 做用 |
---|---|---|
v-bind=attr | :attr | 將數據和標籤幫頂起來 |
v-on:action=actionName | @action=actionName | 綁定事件,事件不須要傳參數能夠省略() |
{{expression}} | 從vue對象中取值 | |
v-if="boolean" | if | |
v-else-if="boolean" | else if | |
v-else | else | |
key | 做爲一種標籤的身份標識 | |
v-show="boolean" | 和v-if的區別是,它是display=none標籤還在 | |
v-for="(item, index) in items" | for循環 | |
:class="{className:boolean}" | 也能夠用數組 | |
v-model="entity" | 雙向綁定表單,其實是兩個指令結合v-bind:value和v-on:input | |
v-html | 輸出真正的 HTML | |
v-once | 寫在標籤上只渲染一次 | |
$forceUpdate |
強制更新數據 | |
export default { name: "Home", created() { console.log("Home組件被建立成功"); } };
未掛載成功的元素不能被獲取到前端
export default { name: "Home", created() { console.log("Home組件被建立成功"); }, mounted(){ console.log("組件被掛載成功") } };
updated(): 當組件中發生變化時vue
export default { name: "Home", created() { console.log("Home組件被建立成功"); }, mounted(){ console.log("組件被掛載成功") }, updated(){ console.log("組件中發生改變時"); } };
其餘java
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="vue.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"> {{msg}} </div> <script type="text/javascript"> var vm = new Vue({ el : "#app", data : { msg : "hi vue", }, //在實例初始化以後,數據觀測 (data observer) 和 event/watcher 事件配置以前被調用。 beforeCreate:function(){ console.log('beforeCreate'); }, /* 在實例建立完成後被當即調用。 在這一步,實例已完成如下的配置:數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。 然而,掛載階段還沒開始,$el 屬性目前不可見。 */ created :function(){ console.log('created'); }, //在掛載開始以前被調用:相關的渲染函數首次被調用 beforeMount : function(){ console.log('beforeMount'); }, //el 被新建立的 vm.$el 替換, 掛在成功 mounted : function(){ console.log('mounted'); }, //數據更新時調用 beforeUpdate : function(){ console.log('beforeUpdate'); }, //組件 DOM 已經更新, 組件更新完畢 updated : function(){ console.log('updated'); } }); setTimeout(function(){ vm.msg = "change ......"; }, 3000); </script> </body> </html>
須要給標籤添加一個key的屬性就能夠了,是由於虛擬dom的問題node
<!-- 當items是數組 --> <ul v-for="(item, index) in items" :key="item"> <li></li> </ul> <!-- 當items是對象,默認是取value --> <ul v-for="value in obj" :key="value"> <li></li> </ul> <!-- 當items是對象,默認是取value,key,index --> <ul v-for="(value,key,index) in obj" > <li></li> </ul>
支持響應式的方法python
pop()刪除最後一個元素jquery
push(a,b...)追加一【多】個元素linux
shift()刪除第一個元素
unshift(a,b...)添加【多】元素到第一個的位置
sort([compare])
reverse()
splice(起始位置,刪除幾個【只填第一個參數就是從第一個位置刪除到完】,從第一個參數位置添加【能夠多個】的元素)
Vue.set(src,index,newValue) 修改src 中index位置值,或者對象賦值,對象直接賦值不起做用
this.$set(a,'title','列表2'); //或者 Vue.set(a,'title','列表2');
不支持響應式的方法
在vue的options中定義filters:{run :function(pram),調用 param|run
關鍵字:computed
更加高效由於使用了緩存
計算屬性的響應式是創建在計算一個響應式的數據上的,它變化纔會更新計算屬性,而方法是每次都計算不使用緩存
計算屬性默認只有 getter ,不過在須要時你也能夠提供一個 setter ,給計算屬性賦值的時候會調用setter方法,取值調用getter方法
computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } }
var data = { a: 1 } var vm = new Vue({ el: '#example', data: data }) vm.$data === data // => true vm.$el === document.getElementById('example') // => true // $watch 是一個實例方法 vm.$watch('a', function (newValue, oldValue) { // 此回調函數將在 `vm.a` 改變後調用 })
<input type="text" v-model="message" />{{message}}
<!-- 失去焦點或者enter纔會更新值--><input type="text" v-model.lazy="message">{{message}}
每當 data 對象發生變化,都會觸發視圖從新渲染。值得注意的是,若是實例已經建立,那麼只有那些 data
中的本來就已經存在的屬性,纔是響應式的。也就是說,若是在實例建立以後,添加一個新的屬性將不是響應式的
借鑑了將一個大的問題拆分紅一個個的小問題這種思想 , 就是"基礎庫"或者「基礎組件",意思是把代碼重複的部分提煉出一個個組件供給功能使用。
組件必須放在vue管理的做用域內,若是是多個標籤必須被一個元素包裹,就是有一個惟一的祖先元素
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script src="../../js/vue.js"></script> <div id="app"> <cpt></cpt> <cpt></cpt> <cpt></cpt> <cpt></cpt> </div> <script> // 1. 建立組件構造器 const component = Vue.extend({ template: ` <div> hello </div>`, }); // 2. 註冊組件 全局組件 Vue.component('cpt', component); const app = new Vue({ el: "#app", data: { message: "hello world" } }); </script> </body> </html>
<div id="app">11 <cpt></cpt> <cpt></cpt> </div> <div id="app2">22 <cpt></cpt> </div> <script> // 1. 建立組件構造器 const component = Vue.extend({ template: ` <div> hello </div>`, }); //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { cpt: component } }); //未註冊組件 const app2 = new Vue({ el: "#app2", data: { message: "hello" } }); </script>
<div id="app">11 <pt></pt> <pt></pt> <pt></pt> </div> <script> /*第1個組件構造器*/ const child = Vue.extend({ template: ` <div> child </div>` }); // 第二建立組件構造器 const parent = Vue.extend({ template: ` <div> parent <cd></cd> </div>`, components: { cd: child } }); //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { pt: parent } }); </script>
組件不會向上級做用域傳遞,只會向下傳遞,孫子沒有在爺爺的做用域註冊的話孫子只能在父親的做用域使用
<div id="app">11 <pt></pt> <pt></pt> <pt></pt> </div> <script> //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { pt: { // 語法糖直接能夠放在註冊的地方 template: ` <div> hello </div>` } } }); </script>
<script src="../../js/vue.js"></script> <div id="app">11 <pt></pt> <pt></pt> <pt></pt> </div> <!--<script type="text/x-template" id="pt"> <div> <div>我是標題</div> </div> </script>--> <template id="pt"> <div> <div>我是tempalte</div> </div> </template> <script> //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { pt: { // 語法糖直接能夠放在註冊的地方 template: "#pt" } } }); </script>
<div id="app">11 <pt></pt> <pt></pt> <pt></pt> </div> <template id="pt"> <div> <div>我是{{title}}</div> </div> </template> <script> //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { pt: { template: "#pt", //是一個函數,且只能訪問本身的數據 data(){ return {title:"title"}; } } } }); </script>
<div id="app"> <pt :msg="msg" :title="title"></pt> </div> <template id="pt"> <div> <div>{{title}}</div> <div>{{msg}}</div> </div> </template> <script> // 1.註冊組件 const pt = { template:"#pt", data() { return {}; }, methods: {}, // props:["title","msg"] 能夠寫成數組或者對象,對象能夠限制類型,對象更好點 props:{ // title:Array, title:{ type: Array, default(){ return []; } }, //也能夠寫成對象的添加更多的限制、給默認值 msg:{ type:String, default:"", required:true, //自定義validator 這個待查閱 validator: function (val) { return val == "hello worl"; } } } } //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { msg: "hello world", title:["aaa","bbb","ccc"] }, //字面量簡寫 pt可替換pt:pt components:{pt} }); </script>
v-on
事件監聽器在 DOM 模板中會被自動轉換爲全小寫 (由於 HTML 是大小寫不敏感的),因此 v-on:myEvent
將會變成 v-on:myevent
——致使 myEvent
不可能被監聽到。<div id="app"> <!-- 不寫參數會默認將$emit事件後傳的參數【可多個】傳出來,寫了參數報錯--> <pt @child-click="parentClick"></pt> </div> <template id="pt"> <div> <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button> </div> </template> <script> // 1.註冊組件 const pt = { template: "#pt", data() { return { categories: [ {id: "aaa", name: "aaa"}, {id: "bbb", name: "bbb"}, {id: "ccc", name: "ccc"}, {id: "ddd", name: "ddd"} ] }; }, methods: { btnClick(ite) { // js中這樣寫不能駝峯,vue能夠 this.$emit('child-click', ite,1); } } }; //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { msg: "hello world", title: ["aaa", "bbb", "ccc"] }, components: {pt}, methods: { parentClick(obj,a) { console.log(obj,a); } } }); </script>
<!--1. num一、num2從父組件傳遞過來 2. 修改num1,dnum1也變,同時傳dnum1給父組件,父組件改變num1,也改變了prop1 3. dnum2一直是dnum1的1%--> <div id="app"> <pt :cnum1="num1" :cnum2="num2" @change1="cc1" @change2="cc2" ></pt> </div> <template id="pt"> <div> <p>props:{{cnum1}}</p> <p>data:{{dnum1}}</p> cnum1<input type="text" :value="dnum1" @input="changeProp1"><br> <p>props:{{cnum2}}</p> <p>data:{{dnum2}}</p> cnum2<input type="text" :value="dnum2" @input="changeProp2"> </div> </template> <script> //局部組件 只在app中的做用域有效 const app = new Vue({ el: "#app", data: { num1: 1, num2: 2 }, methods: { cc1(eve1) { this.num1 = eve1; }, cc2(eve2) { this.num2 = eve2; } }, components: { pt: { template: "#pt", props: { cnum1: { type: Number, default: 3 }, cnum2: { type: Number, default: 4 } }, data() { return { dnum1: this.cnum1, dnum2: this.cnum2, }; }, methods: { changeProp1(event1) { this.dnum1 = event1.target.value; console.log(this.dnum1) if (this.dnum1) { this.dnum1 = parseInt(this.dnum1) this.dnum2 = this.dnum1 / 100; this.$emit('change1', this.dnum1); } else { this.dnum2 = ""; } }, changeProp2(event2) { this.dnum2 = event2.target.value; this.$emit('change2', parseInt(this.dnum2)); } } } } }); </script>
watch監聽對象不能直接監聽,能夠用computed代替對象
語法:
watch:{ 監聽的屬性名(newValue, oldValue){ } }
<script src="../../js/vue.js"></script> <div id="app"> {{message}} <input type="text" v-model="message"> {{demo.name}} <input type="text" v-model="demo.name"> </div> <template id="cd"> <div> aaaaa </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world", demo: { name: "nameObj" } }, computed:{ demoName(){ return this.demo.name; } }, watch: { message(newVal, oldVal) { console.log(newVal, oldVal); }, //不能直接監聽對象 // demo(val) { // console.log(val); // } demoName(val) { console.log(val); } }, components: { cd: { template: "#cd" } } }); </script>
若是是鍵的路徑須要用引號包裹
也能夠外部調用
immediate和handler
watch有一個特色,就是當值第一次綁定的時候,不會執行監聽函數,只有值發生改變纔會執行。若是咱們須要在最初綁定值的時候也執行函數,則就須要用到immediate屬性。
好比當父組件向子組件動態傳值時,子組件props首次獲取到父組件傳來的默認值時,也須要執行函數,此時就須要將immediate設爲true。
**deep: **當須要監聽一個對象的改變時,普通的watch方法沒法監聽到對象內部屬性的改變,只有data中的數據纔可以監聽到變化,此時就須要deep屬性對對象進行深度監聽
<div id="app"> {{demo1.name}} <input type="text" v-model="demo1.name"> {{demo.name}} <input type="text" v-model="demo.name"> <input type="text" v-model="demo2"> </div> <script> const app = new Vue({ el: "#app", data: { message: "hello world", demo: { name: "nameObj" }, demo1: { name: "nameObj" }, demo2:"qweqw" }, computed: { demoName() { return this.demo.name; } }, watch: { //若是是鍵的路徑須要用引號包裹 "demo.name": function (val) { console.log(val); }, // childrens: { //監聽的屬性的名字 // handler:function(val){ // console.log(val.name); // }, // deep: true, //能夠監聽到一個對象的內部屬性變化 // immediate: true // }, // "childrens.name":function (val) { // console.log(val); // } } }); //外部調用 app.$watch("demo2",function (val) { console.log(val) }) </script>
<div id="app"> <tmp ref="a"></tmp> <tmp ref="a"></tmp> <tmp ref="b"></tmp> <button @click="btnClick">打印子組件</button> </div> <template id="tmp"> <div> <p>哈哈哈</p> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world" }, methods:{ btnClick(){ //1. 通常不會用$children來取子組件 // console.log("第一個子組件:",this.$children[0]); // console.log("全部子組件:",this.$children); // 2.$refs.refName|['refName'] console.log("全部組件有ref屬性的組件:",this.$refs); //若是多個相同的引用會取最後一個 console.log("取得固定的ref的元素:",this.$refs["a"]); console.log("取得固定的ref的元素:",this.$refs.b); } }, components: { tmp: { template: "#tmp" } }, }); </script>
<div id="app"> <tmp></tmp> </div> <template id="tmp"> <div> <p>哈哈哈</p> <button @click="btnClick">打印父組件</button> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { tmp: { template: "#tmp", methods: { btnClick() { //1. 不建議使用,會讓組件的耦合加強不夠獨立 console.log("打印直系父組件:", this.$parent); //祖先組件 console.log("打印root組件:", this.$root); } } }, }, });
<!--1. 插槽的基本使用 <slot></slot>--> <!--2. 插槽的默認值 <slot>默認值</slot>--> <div id="app"> <tmp></tmp><br> <tmp></tmp><br> <tmp></tmp><br> <tmp><div>我是插槽</div></tmp> <tmp><i>我是插槽i</i></tmp> </div> <template id="tmp"> <div> <p>哈哈哈</p> <slot><p>我是默認值*******</p></slot> <p>娃娃</p> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { tmp: { template: "#tmp" }, } }); </script>
<div id="app"> <tmp ><a slot="right" href="#">我替換右邊</a></tmp><br> <tmp ><a slot="left" href="#">我替換左邊</a></tmp><br> <tmp><a href="#">我替換沒名字的</a></tmp><br> </div> <template id="tmp"> <div> <slot name="left"><p>我是默認值left</p></slot> <slot name="center"><p>我是默認值center</p></slot> <slot name="right"><p>我是默認值right</p></slot> <slot><p>我是默認值沒有名字</p></slot> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world" }, components: { tmp: { template: "#tmp" }, } });
<div id="app"> <!-- 在誰的做用域用誰的變量--> <cp v-show="isShow"></cp> </div> <template id="cp"> <div v-show="isShow"><!-- div父元素初始化的時候不受影響 --> <a href="">aaa</a> <button v-show="isShow">按鈕</button> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world", isShow: true }, components: { cp: { template: "#cp", data() { return { isShow: false }; } } } }); </script>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="../../js/vue.js"></script> <div id="app"> <cp> <!-- slotData:相似於該組件的對象,2.5以前要用template--> <template slot-scope="slotData"> <!-- 取得綁定在組件中的數據--> <span v-for="item in slotData.datas">{{item}}-</span> </template> </cp> <cp> <template slot-scope="slotData"> <!-- join方法將數組拼接成字符串--> <span>{{slotData.datas.join(' * ')}}</span> </template> </cp> </div> <template id="cp"> <div> <!-- 做爲傳遞的數據--> <slot :datas="languages"> <ul> <li v-for="item in languages">{{item}}</li> </ul> </slot> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello world", }, components: { cp: { template: "#cp", data() { return { languages: ['java', 'javascript', 'css', 'html', 'vb', 'python'] }; } } } }); </script> </body> </html>
把功能進行劃分,將同一類型的代碼整合在一塊兒,因此模塊的功能相對複雜,但都同屬於一個業務
// ;是爲了防止其餘的導入js相互影響 ;var xm01 = (function xiaoming01() { return { aa:"asdas", flag: true }; }()) //js文件2 ;(function () { if (xm01.flag) { alert("xm01.flag:" + xm01.flag); } }());
組件化相似模塊化的更細粒度,組件充當了基本類庫同樣的東西目的是複用拓展性,模塊主要是以功能區分類別劃分儘可能隔離其餘業務
xiaoming01.js
// es6的導出,02中導入 export let exa = "222"; let exa1 = "333"; let exb = "333"; export {exb, exa1}; export function fun(){ console.log("asasddsds"); } //export default :import的時候能夠自定義命名,一個js中只能有一個default let aaa="export default"; export default aaa;
xiaoming02.js
// 導入 ,這裏須要寫上.js import {exa, exa1, exb} from "./xiaoming01.js"; // 01 console.log(exa1, exb); //導入default能夠自定義命名 import asd from "./xiaoming01.js"; console.log('export:',asd); //導入所有的導出,而且重命名 import * as all from "./xiaoming01.js"; console.log(all); console.log(all.default)
01-es6.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="./xiaoming01.js" type="module"></script> <script src="./xiaoming02.js" type="module"></script> </head> <body> 沒有使用導入導出的話: Uncaught ReferenceError: flag is not defined at xiaoming02.js:3 之前是能夠執行的先在不知道怎麼執行不了了 </body> </html>
node package manager , node包管理工具
查看版本:npm -v
卸載安裝的包 npm uninstall 包名 或 npm remove 包名
查看包的詳細信息, npm info 包名
查看一個包存在的全部版本號 npm view 包名 versions
查看指定包當前的最新版本 npm view 包名 version
下載指定版本的包 npm install 包名@1.8
npm list 查看項目安裝了哪些包 或 npm ls
npm install jquery --save 或 npm i jquery -S 下載生產包
npm install jquery --save-dev 或 npm i jquery -D 下載開發依賴包
npm ls jquery 查看當前安裝包的版本
npm config set registry https://registry.npm.taobao.org 更改 npm 的下載鏡像爲淘寶鏡像
npm help npm幫助文檔
使用和linux有的很像
*webpack* 是一個現代 JavaScript 應用程序的*靜態模塊打包器(module bundler)*。當 webpack 處理應用程序時,它會遞歸地構建一個*依賴關係圖(dependency graph)*,其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 *bundle*(捆,束),它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其打包爲合適的格式以供瀏覽器使用。
入口js
//commonjs規範 const {add} = require('./mathUtil.js'); console.log(add(1,3)); //es6規範 import {result} from "./es6.js"; console.log(result);
es6規範
const result = 45456; export {result};
function add(a, b) { return a + b; } module.exports = {add};
//node的包裏面的path模塊,用來拼接絕對路徑 const path = require('path'); //這裏要用commonjs導出,不能用es6 module.exports = { //打包轉換的調用入口和main方法相似 entry: './src/main.js', ouput: { //必須使用絕對路徑,path.resolve(__dirname,'dist')返回絕對路徑 path: path.resolve(__dirname,'dist'), filename: 'bundle.js' } };
{ "name": "meetpackage", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", //npm run build 會在這個配置文件中找webpack命令,這個使用的是本地的命令, //不是全局的webpack,本地是針對於你的這個開發項目 "build":"webpack" }, "author": "", //開發的依賴 "devDependencies": { "webpack": "^3.6.0" }, //開源才須要這個,json中不能註釋 "license": "ISC" }
-
-save 會把依賴包名稱添加到 package.json 文件 dependencies 下;
-
-save-dev 則添加到 package.json 文件 devDependencies 鍵下;
//node的包裏面的path模塊,用來拼接絕對路徑 const path = require('path'); //這裏要用commonjs導出,不能用es6 module.exports = { entry: './src/main.js', output: { //必須使用絕對路徑 path: path.resolve(__dirname,'dist'), filename: 'bundle.js', //爲全部的url相關的添加路徑 publicPath:'dist/' }, module:{ rules: [ { test: /\.css$/, // style-loader將模塊的導出做爲樣式添加到 DOM 中 // loader解析 CSS 文件後,使用 import 加載,而且返回 CSS 代碼 // 從右到左的順序加載 use: [ 'style-loader', 'css-loader' ] }, // { // test: /\.(png|jpg|gif)$/, // use: [ // { // loader: 'url-loader', // options: { // //限制圖片大小,大於limit會找file-loader // limit: 9999 // } // } // ] // }, // 在使用webpack進行打包時,對圖片路徑的處理方法經常使用的有兩種,一種是file-loader, // 一種是url-loader,當咱們使用其中一種是,請把另外一種刪掉,否則會出現圖片沒法正常顯示的問題 { test: /\.(png|jpg|gif)$/, use: [ { loader: 'file-loader', options: { //name是文件名,hash取8位,ext是拓展名 name:'img/[name].[hash:8].[ext]' } } ] }, { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } } ] } };
npm install vue -save
不寫路徑默認從node_modules引入 import Vue from 'vue'
runtime-only:是運行的時候代碼不能包含任意一個template標籤
runtime-compiler:代碼中能夠有template標籤
module:{ resolve:{ alias:{ // vue$正則,表示導入的時候會檢測vue指向的文件夾,若是這裏不指定,會去找默認的runtime-only 'vue$':'vue/dist/vue.esm.js' } }
//使用vue import Vue from 'vue'; const App = { template: ` <h2>{{msg}}</h2> `, data() { return { msg: 'hello world' }; } }; new Vue({ el: '#app', // template和el關係是,這裏的template會替換el的標籤 template: `<App/>`, components: { App } });
<template> <h2>{{msg}}</h2> <span class="title">{{tit}}</span> </template> <script> export default { name: "App", data() { return { msg: 'hello world', tit:'title' }; } } </script> <style scoped> .title{ color: red; } </style>
全局安裝:能夠不用
npm install webpack-dev-server -g
開發環境:
npm install webpack-dev-server -save -dev
配置參數:
--content-base //設定webpack-dev-server的director根目錄。若是不進行設定的話,默認是在當前目錄下。 --quiet: //控制檯中不輸出打包的信息,開發中通常設置爲false,進行 打印,這樣查看錯誤比較方面 --no-info: // 不顯示任何信息 --colors: //對信息進行顏色輸出 --no-colors: //對信息不進行顏色輸出 --compress: //開啓gzip壓縮 --host <hostname/ip>: //設置ip --port <number>: //設置端口號,默認是:8080 --inline: //webpack-dev-server會在你的webpack.config.js的入口配置文件中再添加一個入口, --hot: //開發熱替換 --open: //啓動命令,自動打開瀏覽器 --history-api-fallback: //查看歷史url
兩種方式:
plugins: [ new webpack.BannerPlugin('最終版權是小明'), //打包靜態資源,而且指定模板 new htmlWebpackPlugin({ template:`index.html` }), //壓縮js new UglifyJsWebpackPlugin(), //熱加載,不會所有加載,只加載改動的地方,配置了hot就須要配置,直接在命令中使用--hot就不須要配置這個插件 // new webpack.HotModuleReplacementPlugin() ], // devServer: { // contentBase: 'src', // port: 80, // hot:true // },
報錯多是版本問題
//node的包裏面的path模塊,用來拼接絕對路徑 const path = require('path'); const webpack = require('webpack'); const htmlWebpackPlugin = require('html-webpack-plugin'); const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin'); //這裏要用commonjs導出,不能用es6 module.exports = { entry: './src/main.js', output: { //必須使用絕對路徑 path: path.resolve(__dirname, 'dist'), filename: 'bundle.js', //爲全部的url相關的添加路徑 // publicPath: 'dist/' }, module: { rules: [ { test: /\.css$/, // style-loader將模塊的導出做爲樣式添加到 DOM 中 // loader解析 CSS 文件後,使用 import 加載,而且返回 CSS 代碼 // 從右到左的順序加載 use: ['style-loader', 'css-loader'] }, // { // test: /\.(png|jpg|gif)$/, // use: [ // { // loader: 'url-loader', // options: { // //限制圖片大小,大於limit會找file-loader // limit: 9999 // } // } // ] // }, // 在使用webpack進行打包時,對圖片路徑的處理方法經常使用的有兩種,一種是file-loader, // 一種是url-loader,當咱們使用其中一種是,請把另外一種刪掉,否則會出現圖片沒法正常顯示的問題 { test: /\.(png|jpg|gif)$/, use: [ { loader: 'file-loader', options: { //name是文件名,hash取8位,ext是拓展名 name: 'img/[name].[hash:8].[ext]' } } ] }, { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }, { test: /\.vue$/, use: { loader: 'vue-loader' } } ] }, resolve: { // 這寫拓展名能夠省略 extensions: ['.css', '.js', '.vue'], alias: { // vue$正則,表示導入的時候會檢測vue指向的文件夾,若是這裏不指定,會去找默認的runtime-only 'vue$': 'vue/dist/vue.esm.js' } }, plugins: [ new webpack.BannerPlugin('最終版權是小明'), //打包靜態資源,而且指定模板 new htmlWebpackPlugin({ template:`index.html` }), //壓縮js new UglifyJsWebpackPlugin(), //熱加載,不會所有加載,只加載改動的地方,配置了hot就須要配置,直接在命令中使用--hot就不須要配置這個插件 // new webpack.HotModuleReplacementPlugin() ], // devServer: { // contentBase: 'src', // port: 80, // hot:true // }, };
//node的包裏面的path模塊,用來拼接絕對路徑 const path = require('path'); const webpack = require('webpack'); const htmlWebpackPlugin = require('html-webpack-plugin'); //這裏要用commonjs導出,不能用es6 module.exports = { entry: './src/main.js', output: { //必須使用絕對路徑 path: path.resolve(__dirname, '../dist'), filename: 'bundle.js', }, module: { rules: [ { test: /\.css$/, // style-loader將模塊的導出做爲樣式添加到 DOM 中 // loader解析 CSS 文件後,使用 import 加載,而且返回 CSS 代碼 // 從右到左的順序加載 use: ['style-loader', 'css-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'file-loader', options: { //name是文件名,hash取8位,ext是拓展名 name: 'img/[name].[hash:8].[ext]' } } ] }, { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }, { test: /\.vue$/, use: { loader: 'vue-loader' } } ] }, resolve: { // 這寫拓展名能夠省略 extensions: ['.css', '.js', '.vue'], alias: { // vue$正則,表示導入的時候會檢測vue指向的文件夾,若是這裏不指定,會去找默認的runtime-only 'vue$': 'vue/dist/vue.esm.js' } }, plugins: [ new webpack.BannerPlugin('最終版權是小明'), //打包靜態資源,而且指定模板 new htmlWebpackPlugin({ template: `index.html` }) ], };
dev.config.js : 存放開發時配置
const WebpackMerge = require('webpack-merge'); const baseConfig = require('./base.config'); module.exports = WebpackMerge(baseConfig, { devServer: { contentBase: 'src', port: 80, inline: true } });
prod.config.js : 存放生產時配置
const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin'); const WebpackMerge = require('webpack-merge'); const baseConfig = require('./base.config'); module.exports = WebpackMerge(baseConfig, { plugins: [ //壓縮js new UglifyJsWebpackPlugin() ] });
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --config ./build/dev.config.js", "build": "webpack --config ./build/prod.config.js" },
使用webpack,也能夠不用配置文件本身在命令後指定參數,如下是使用配置文件
使用npm,會找到package.json找到對應的script裏的命令執行,實際上仍是調用了webpack命令
介紹:
安裝:
卸載以前版本
拉取v2的模板
npm install -g @vue/cli-init
vue init webpack projectName
零配置
隱藏build和config目錄,能夠在node-modules/@vue/cli-service
要修改配置須要根目錄建立一個vue.config.js
module.exports={};
基於webpack4
提供vue ui命令,圖形化操做
移除static,新增public目錄將index.html移動到下面
項目名不能有大寫
vue create projectName
會默認建立一個.git文件夾
自定義配置:
module.exports = { configureWebpack: { resolve: { // extensions:[], //配置別名 alias: { 'assets': '@/assets', 'components': '@/components', 'network': '@/network', 'common': '@/commom', 'views': '@/views', } } } };
root = true [*] charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true
vue ui 打開圖形管理界面
runtime-only:是運行的時候代碼不能包含任意一個template標籤
runtime-compiler:代碼中能夠有template標籤
template加載過程:
template - 》parse - 》ast 抽象語法樹 - 》compiler - 》render(h)- 》 virtual Dom - 》UI真實dom
1比2性能更高,代碼更少(少6kb)
//runtime-compiler // The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', components: { App }, template: '<App/>' }) import Vue from 'vue' import App from './App' Vue.config.productionTip = false //runtime-only,這個h是一個createElement('tagName',{attrName:'attrVal'},['innerHtml']) //在vue中也能夠傳一個template對象靠vue-template-compiler解析成render(),也能夠遞歸建立 /* eslint-disable no-new */ new Vue({ el: '#app', render: h => h(App) })
通常使用vue的插件都要用Vue.use(插件)
安裝路由:npm install vue-router --save 由於生產也須要路由
導入:
import Vue from 'vue' //1. 導入插件 import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path: '/', name: 'HelloWorld', component: HelloWorld } ]; //4. 傳入路由配置,導出路由對象 export default new Router({ routes })
import Vue from 'vue' import App from './App' //只寫目錄默認會找 index.js import router from './router' Vue.config.productionTip = false new Vue({ el: '#app', router, render: h => h(App) })
<div id="app"> <router-link to="/home">首頁</router-link> <!-- 至關於佔位符 --> <router-view></router-view> <router-link to="/about">詳情</router-link> </div>
經常使用屬性
tag 、replace
<!-- tag設置替換成什麼標籤 --> <!-- replace表示禁用了返回前進按鈕,是使用了history.replaceState() --> <router-link to="/home" tag='button' replace>首頁</router-link>
配置默認的active的樣式
.router-link-active{ color: #f00 }
自定義樣式:手動一個一個標籤的寫
<!--active-class 自定義點擊後的樣式 --> <router-link to="/home" tag='button' replace active-class="active">首頁</router-link>
配置全局的active-class
export default new Router({ routes, mode:'history', linkActiveClass:'active' })
const routes = [ { path:'/', redirect:'/home' }, { path: '/home', name: 'Home', component: Home }, { path:'/about', name:'About', component:About } ];
//4. 傳入路由配置,導出路由對象 export default new Router({ routes, mode:'history' })
<template> <div id="app"> <button @click="homeClick">首頁</button> <button @click="aboutClick">詳細</button> <router-view></router-view> </div> </template> <script> export default { name: 'App', methods:{ //router會給每一個組件傳$router homeClick(){ // this.$router.push('/home'); this.$router.replace('/home'); }, aboutClick(){ // this.$router.push('/about'); this.$router.replace('/about'); } } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
建立一個vue組件:User.vue
<template> <div> <h2>我的信心</h2> <h3></h3> </div> </template> <script> export default { name:'User', } </script> <style> </style>
配置路由:index.js
import Vue from 'vue' import User from '../components/User.vue' //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path:'/user', component:User } ]; //4. 傳入路由配置,導出路由對象 export default new Router({ routes, mode:'history', linkActiveClass:'active' })
加入路由到目標組件:Vue.vue
<template> <div id="app"> <router-link to="/user" replace>用戶</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', } </script> <style> .active{ color: rgb(209, 15, 25) } </style>
導入組件到入口 : main.js
import Vue from 'vue' import App from './App' //只寫目錄默認會找 index.js import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, render: h => h(App) })
設置動態路由:index.js
import Vue from 'vue' import User from '../components/User.vue' //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path:'/user/:userName', component:User } ]; //4. 傳入路由配置,導出路由對象 export default new Router({ routes, mode:'history', linkActiveClass:'active' })
配置頁面的url: Vue.vue
<template> <div id="app"> <router-link v-bind:to="'/user/'+userName" replace>用戶</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', data(){ return { userName:'xiaoming' } } } </script> <style> .active{ color: rgb(209, 15, 25) } </style>
獲取動態路由中的參數:User.vue
<template> <div> <h2>我的信心</h2> <h3>{{userName}}</h3> </div> </template> <script> export default { name:'User', computed:{ userName(){ return this.$route.params.userName; } } } </script> <style> </style>
路由配置中props
被設置爲 true
,route.params
將會被設置爲組件屬性。
編程式路由
// 字符串 router.push('home') // 對象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意: path和params 不共存params會被忽略,path和query 能夠。name和params也能夠
const userId = '123' //命名路由 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 這裏的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
一樣的規則也適用於 router-link
組件的 to
屬性
有時候,同一個路徑能夠匹配多個路由,此時,匹配的優先級就按照路由的定義順序:誰先定義的,誰的優先級就最高。
若是把全部的js都打包到app中,js將會很大,訪問的時候會有等待時間,因此把不一樣的路由對應的組件分割成不一樣的代碼塊,而後當路由被訪問的時候加載對應的資源,就更加高效了
import Vue from 'vue' //替換成懶加載 // import Home from '../components/Home.vue' // import About from '../components/About.vue' // import User from '../components/User.vue' //懶加載: const Home = ()=>import('../components/Home.vue') const About = ()=>import('../components/About.vue') const User = ()=>import('../components/User.vue') //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path:'/', redirect:'/home' }, { path: '/home', name: 'Home', component: Home }, { path:'/about', name:'About', component:About }, { path:'/user/:userName', component:User } ]; //4. 傳入路由配置,導出路由對象 export default new Router({ routes, mode:'history', linkActiveClass:'active' })
import Vue from 'vue' //替換成懶加載 // import Home from '../components/Home.vue' // import About from '../components/About.vue' // import User from '../components/User.vue' //懶加載: const Home = () => import('../components/Home.vue') const About = () => import('../components/About.vue') const User = () => import('../components/User.vue') const HomeChild = () => import ('../components/HomeChild.vue') //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, children: [ { path: '', // redirect:'child' }, { //這裏不能同/開頭,會自動加上 path: 'child', name: 'HomeChild', component: HomeChild }] }, { path: '/about', name: 'About', component: About }, { path: '/user/:userName', component: User } ]; //4. 傳入路由配置,導出路由對象 export default new Router({ routes, mode: 'history', linkActiveClass: 'active' })
<template> <div> <h2>首頁11</h2> <router-link to="/home/child">child</router-link> <router-view></router-view> </div> </template> <script> export default { name:'Home' } </script> <style> </style>
<template> <div><span>我的檔案</span> <span>{{$route.query}}</span><br> <span>query.name: {{$route.query.name}}</span> </div> </template> <script> export default { name: "Profile" } </script> <style scoped> </style>
const Profile = () => import('../components/Profile') { path: '/profile', component: Profile }
<template> <div id="app"> <router-link to="/home" tag='button' replace >首頁</router-link> <router-link to="/about" replace>詳情</router-link> <router-link :to="'/user/'+userName" replace>用戶</router-link> <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>檔案</router-link> <!-- <button @click="homeClick">首頁</button> <button @click="aboutClick">詳細</button> --> <router-view></router-view> </div> </template>
注意導航守衛並無應用在跳轉(redirect)路由上,而僅僅應用在其目標上。爲redirect的路由添加一個 beforeEach
或 beforeLeave
守衛並不會有任何效果
全部的路由都會被過濾,也能夠在特定的組件內建立局部守衛
主要監聽頁面的跳轉
from從哪一個組件來的
to去跳轉到哪一個組件
next()
import Vue from 'vue' //替換成懶加載 // import Home from '../components/Home.vue' // import About from '../components/About.vue' // import User from '../components/User.vue' //懶加載: const Home = () => import('../components/Home.vue') const About = () => import('../components/About.vue') const User = () => import('../components/User.vue') const HomeChild = () => import('../components/HomeChild.vue') const Profile = () => import('../components/Profile') //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, meta: { title: '首頁' }, children: [ { path: '', // redirect:'child' }, { //這裏不能同/開頭,會自動加上 path: 'child', name: 'HomeChild', component: HomeChild, }] }, { path: '/about', name: 'About', component: About, meta: { title: '詳情' }, }, { path: '/user/:userName', component: User, meta: { title: '用戶' }, }, { path: '/profile', component: Profile, meta: { title: '檔案' }, } ]; const router = new Router({ routes, mode: 'history', linkActiveClass: 'active' }) router.beforeEach((to, from, next) => { next() //匹配path中的meta對象的title document.title = to.matched[0].meta.title console.log(to); // console.log(from); // console.log("next: "+next); }) //4. 傳入路由配置,導出路由對象 export default router
import Vue from 'vue' //懶加載: const Home = () => import('../components/Home.vue') //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, meta: { title: '首頁' }, children: [ { path: '', // redirect:'child' }, { //這裏不能同/開頭,會自動加上 path: 'child', name: 'HomeChild', component: HomeChild, beforeEnter: (to, from, next) => { console.log("獨享守衛"); next() } }] } ]; const router = new Router({ routes, mode: 'history', linkActiveClass: 'active' }) //4. 傳入路由配置,導出路由對象 export default router
import Vue from 'vue' //懶加載: const Home = () => import('../components/Home.vue') //1. 導入插件 import Router from 'vue-router' //2. 使用插件 Vue.use(Router) //3. 建立路由配置 const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, meta: { title: '首頁' } }, ]; const router = new Router({ routes, mode: 'history', linkActiveClass: 'active' }) //前置鉤子 hook,像filter同樣 router.beforeEach((to, from, next) => { next() //匹配path中的meta對象的title document.title = to.matched[0].meta.title console.log(to); }) //後置鉤子 router.afterEach((to,from)=>{ console.log("在跳轉以後調用"); }) //4. 傳入路由配置,導出路由對象 export default router
是vue的一個組件:保證一些組件進入緩存不用你每次請求解析資源,提升效率,在顯示的地方配置
<template> <div id="app"> <router-link to="/home" tag="button" replace>首頁</router-link> <router-link to="/about" replace>詳情</router-link> <router-link :to="'/user/'+userName" replace>用戶</router-link> <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>檔案</router-link> <button @click="toProfile">檔案2</button> <!-- <button @click="homeClick">首頁</button> <button @click="aboutClick">詳細</button>--> <!-- <router-view></router-view> --> <!-- 保存到緩存中 --> <keep-alive> <router-view></router-view> </keep-alive> </div> </template>
keep-alive的組件纔可使用activated()、deactivated()
<template> <div> <h2>首頁11</h2> <router-link :to="{path:'/home/child',query:{content:'child1'}}">child</router-link> <router-link :to="toChild2">child2</router-link> <router-view></router-view> </div> </template> <script> export default { name: "Home", data() { return { toChild2: { path: "/home/child2", query: { content: "child2" } }, path: "/home/child", query:{ childContent:'child1' } }; }, methods: {}, created() { console.log("Home組件被建立成功"); }, mounted() { console.log("組件被掛載成功"); }, updated() { console.log("組件中發生改變時"); }, destroyed() { console.log("home destroyed"); }, activated() { console.log("home 激活"); this.$router.push(this.path) }, deactivated() { console.log("home 離開"); }, beforeRouteLeave(to, from, next) { console.log('before leave home'); this.path = this.$route.path; console.log(this.path); next(); } }; </script> <style> </style>
keep-alive 的exclude、include屬性
<keep-alive exclude="Profile"> <router-view></router-view> </keep-alive>
export default { name: "Profile", created() { console.log("profile created"); }, destroyed() { console.log("profile destroyed"); } };
/*style中引用要用@import */
準備好tabbar.vue,調好樣式,預留出來一個插槽,用來放具體的tabbar的item
<template> <div id="tab-bar"> <slot></slot> </div> </template> <script> export default { name: "TabBar", } </script> <style scoped> #tab-bar { display: flex; background-color: #fdfdff; /*顯示在最下面和屏幕等寬*/ position: fixed; left: 0; right: 0; bottom: 0; /*陰影 fgba(最後是0.1表示透明度)*/ box-shadow: 0 -1px 1px rgba(100, 100, 100, .1); } </style>
封裝tab-bar-item
<template> <div class="tab-bar-item" @click="itemClick"> <div v-if="!isActive"> <slot name="item-icon"></slot> </div> <div v-else> <slot name="item-icon-active"></slot> </div> <div :class="{active:isActive}"> <slot name="item-text"></slot> </div> </div> </template> <script> export default { name: "TabBarItem", props:{ path:{ type:String } }, data() { return { // isActive: true } }, computed:{ isActive(){ return this.$route.path.indexOf(this.path) !== -1 } }, methods:{ itemClick(e){ this.$router.replace(this.path) } } } </script> <style scoped> .tab-bar-item { flex: 1; text-align: center; /*通常移動端的tabbar都是49px*/ height: 49px; font-size: 14px; } .tab-bar-item img { width: 24px; height: 24px; margin-top: 3px; margin-bottom: 2px; /*能夠去掉圖片下面的三個像素*/ vertical-align: bottom; } .active { color: red; } </style>
註冊到app.vue中
<template> <div id="app"> <router-view></router-view> <tab-bar> <tab-bar-item path="/home"> <img slot="item-icon" src="./assets/images/tabbar/home.png" alt="首頁"> <img slot="item-icon-active" src="./assets/images/tabbar/home_active.png" alt=""> <div slot="item-text">首頁</div> </tab-bar-item> <tab-bar-item path="/category"> <img slot="item-icon" src="./assets/images/tabbar/category.png" alt=""> <img slot="item-icon-active" src="./assets/images/tabbar/category_active.png" alt=""> <div slot="item-text">分類</div> </tab-bar-item> <tab-bar-item path="/cart"> <img slot="item-icon" src="./assets/images/tabbar/cart.png" alt=""> <img slot="item-icon-active" src="./assets/images/tabbar/cart_active.png" alt=""> <div slot="item-text">購物車</div> </tab-bar-item> <tab-bar-item path="/profile"> <img slot="item-icon" src="./assets/images/tabbar/profile.png" alt=""> <img slot="item-icon-active" src="./assets/images/tabbar/profile_active.png" alt=""> <div slot="item-text">個人</div> </tab-bar-item> </tab-bar> </div> </template> <script> import TabBar from "./components/tabbar/TabBar"; import TabBarItem from "./components/tabbar/TabBarItem"; export default { name: 'App', components: { TabBar, TabBarItem } } </script> <style> /*style中引用要用@*/ @import "./assets/css/base.css"; </style>
能夠優化class,顏色直接寫死不合適
還能夠從父組件傳過來,而後綁定style來設置
配置別名:\build\webpack.base.conf.js
resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': resolve('src'), 'assets': resolve('src/assets'), 'components': resolve('src/components'), 'views': resolve('src/views'), } },
項目中使用
html中: 前面要加 ~
<tab-bar-item path="/home" activeColor="blue"> <img slot="item-icon" src="~assets/images/tabbar/home.png" alt="首頁" /> <img slot="item-icon-active" src="~assets/images/tabbar/home_active.png" alt /> <div slot="item-text">首頁</div> </tab-bar-item>
import中使用
import TabBarItem from "components/tabbar/TabBarItem";
根目錄下新建vue.config.js
在vue.config.js中的chainWebpack中配置config.resolve.alias.set('@', resolve('src')).set('components', resolve('src/components'));
是異步編程的一種解決方案
new Promise((resolve, reject) => { setTimeout(() => { resolve('傳入then 中的 data') }, 1500) }).then(data => { console.log(data); return new Promise((resolve, reject) => { setTimeout(() => { // resolve('內部的resolve') reject('內部的reject') }, 1500) }) }).catch(data => { console.log(data); })
promise異步完成後會有三種狀態
promise的另外一種寫法
new Promise((resolve, reject) => { setTimeout(() => { resolve('傳入then 中的 data') // reject('失敗') }, 1500) }).then(data => { console.log(data); },reject => { console.log(reject); })
再簡化
// new Promise(resolve) ==>Promise.resolve(data) ==> data //throw 'msg'也會被catch()捕獲 new Promise((resolve, reject) => { setTimeout(() => { resolve('第一層...') }, 1500) }).then(data => { console.log(data); return Promise.resolve('第二層...') // return Promise.reject('額鵝鵝鵝') throw 'dsadsa' }).then(data=>{ console.log(data); return 'aaa' }).then(data=>{ console.log(data); }).catch(err=>{ console.log(err); })
Promise.all([ new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve('1111111') },1000) }), new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve('222222') },2000) }) ]).then(data=>{ //1111111,222222 console.log(data.toString()) })
經過提交 mutation 的方式,而非直接改變 store.state.count
,是由於咱們想要更明確地追蹤到狀態的變化。這個簡單的約定可以讓你的意圖更加明顯,這樣你在閱讀代碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓咱們有機會去實現一些能記錄每次狀態改變,保存狀態快照的調試工具。有了它,咱們甚至能夠實現如時間穿梭般的調試體驗。
因爲 store 中的狀態是響應式的,在組件中調用 store 中的狀態簡單到僅須要在計算屬性中返回便可。觸發變化也僅僅是在組件的 methods 中提交 mutation。
actions步驟能夠省略,通常異步的操做放在actions中完成後放在mutations中
mutations只能是同步的操做,devtools監聽不到異步操做
store用法
state中全部的已定義的屬性都是響應式的,新加入的不被響應:由於屬性初始化後,都被一個dep對象=【watcher,watcher..】監控,後面加入的不受監控
npm install vuex --save
新建、src/store/index.js
import Vue from 'vue' import Vuex from 'vuex' //1.安裝,底層會調用Vuex.install Vue.use(Vuex) // 2.建立對象 const store = new Vuex.Store({ state: { count: 0 }, mutations: { //state必須傳,默認會傳進來 increment(state) { state.count++ } }, actions: {}, getters: {}, modules: {} }) // 3.導出store對象 export default store
import Vue from 'vue' import App from './App' import store from "./store"; Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', store, render: h => h(App) })
<template> <div id="app"> <h2>{{$store.state.count}}</h2> <button @click="increment">+</button> <hello-vuex></hello-vuex> </div> </template> <script> import HelloVuex from "./components/HelloVuex"; export default { name: 'App', methods:{ increment(){ this.$store.commit('increment') } }, components: { HelloVuex } } </script> <style> </style>
<template> <div> <h2>{{$store.state.count}}</h2> </div> </template> <script> export default { name: "HelloVuex" } </script> <style scoped> </style>
有點像computed的概念
<template> <div id="app"> <h2>{{$store.state.count}}</h2> <button @click="increment">+</button> <h2>年齡大於20:{{$store.getters.more20Person}}</h2> <h2>年齡大於20個數:{{$store.getters.more20PersonCount}}</h2> <h2>年齡大於age個數:{{$store.getters.moreAgePerson(13)}}</h2> <hello-vuex></hello-vuex> </div> </template> <script> import HelloVuex from "./components/HelloVuex"; export default { name: 'App', methods:{ increment(){ this.$store.commit('increment') } }, components: { HelloVuex } } </script> <style> </style>
import Vue from 'vue' import Vuex from 'vuex' //1.安裝,底層會調用Vuex.install Vue.use(Vuex) // 2.建立對象 const store = new Vuex.Store({ state: { count: 0, persons: [ {name: 'a', age: 12}, {name: 'b', age: 23}, {name: 'c', age: 32}, {name: 'd', age: 24} ] }, mutations: { //state必須傳,默認會傳進來 increment(state) { state.count++ } }, actions: {}, //最多隻能寫兩個參數時state,getters,默認會傳進來 getters: { more20Person(state) { return state.persons.filter(per=>per.age>20) }, more20PersonCount(state,getters){ // 這裏不用寫括號 return getters.more20Person.length }, //返回一個函數能夠傳動態的參數 moreAgePerson(state){ return (age)=>{ return state.persons.filter(per=>per.age>age) } } }, modules: {} }) // 3.導出store對象 export default store
//store/index.js mutations: { //state必須傳,默認會傳進來 increment(state) { state.count++ }, add(state,num){ state.count +=num } } //app.vue methods:{ increment(){ this.$store.commit('increment') }, add(num){ this.$store.commit('add',num) } }
第二種提交風格
inc(num){ this.$store.commit({ type:'inc', num }) }
mutations: { //state必須傳,默認會傳進來 increment(state) { state.count++ }, add(state,num){ state.count +=num }, //當成對象處理參數 inc(state,payLoad){ state.count +=payLoad.num } }
update(state){ //響應式 // state.persons.push({name:'e',age:99}) //響應式 // state.person={name:'f',age:101} //新加的屬性不會被監控,只有在其餘任意的屬性變化一次後他會刷新一次 // state.person.add=111 // state.person['address']=222 //刪除一個對象的屬性 // delete state.person.age //vue set value是響應式的,key必須是字符串 // Vue.set(state.person,'asd','vue set value是響應式的') Vue.delete(state.person,'age') }
避免寫錯,定義一個常量對象,在使用的文件中導入
定義
[const](){}
//mutation-type.js export const INCREMENT='increment' export const ADD='add' export const INC='inc' export const UPDATE='update' import {INCREMENT,ADD,UPDATE,INC} from "./mutation-type"; //app.vue update(){ this.$store.commit({ type:UPDATE, }) } //index.js mutations: { //state必須傳,默認會傳進來 [INCREMENT](state) { state.count++ }, [ADD](state,num){ state.count +=num }, //當成對象處理參數 [INC](state,payLoad){ state.count +=payLoad.num }, [UPDATE](state){ Vue.delete(state.person,'age') } }
action處理異步操做:
//app.vue aUpdate(){ // this.$store.dispatch('aUpdate',{ // msg:'參數信息', // success:(data)=>{console.log(data)} // }) //第二種方法,異步函數返回的promise對象 this.$store.dispatch('aUpdate',{ msg:'參數信息' }).then(res=>{ console.log('完成異步操做'); console.log(res); }) } //index.js actions: { // aUpdate(context,payload) { // // console.log('默認參數是上下文對象: ',context) // setTimeout(function () { // context.commit('aUpdate',payload) // }, 1000) // } //第二種方式返回一個promise對象,在調用處可使用 aUpdate(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('aUpdate', payload) resolve(12312) }, 1000) }) } }
顯示:app.vue
<h2>-------------state--modules的內容---------</h2> <h2>{{$store.state.a.name}}</h2> <h2>{{$store.getters.getModuleA}}</h2> <h2>{{$store.getters.getModuleA_add('age')}}</h2> <h2>{{$store.getters.getModuleA_add_root}}</h2> <button @click="moduleA">模塊a修改name</button> <button @click="asyncUpdateModuleA">異步模塊a修改name</button> methods:{ moduleA() { this.$store.commit('aUpdate','模塊a名字修改') }, asyncUpdateModuleA(){ this.$store.dispatch('asyncUpdateModuleA') } }
index.js
modules: { a:{ //須要指定模塊名,能夠和父模塊同名 state:{name:'module_a',person:123}, //和父模塊同名會報錯,能夠直接訪問不須要指定模塊名 getters:{ getModuleA(state){ return state.name+'_getModuleA' }, getModuleA_add(state,getters){ return (age) => { return getters.getModuleA+age } }, //三個默認參數 getModuleA_add_root(state,getters,rootState){ return state.name+getters.getModuleA+'_add_'+rootState.count } }, // 和mutations使用差很少 actions:{ //也可使用對象的解構,詳見es6 asyncUpdateModuleA(context){ setTimeout(()=>{ context.commit('aUpdate','異步修改子模塊') },1000) } }, mutations:{ //和父模塊名字相同都會調用,先調用父模塊的,因此不要定義相同的名字 aUpdate(state,payload){ state.name=payload console.log('child mutations 被調用') } }, modules:{} }, //模塊b b:ModuleB }
import Vue from 'vue' import Vuex from 'vuex' import mutations from "./mutations"; import actions from "./actions"; import getters from "./getters"; import module_a from "./modules/module_a"; //1.安裝,底層會調用Vuex.install Vue.use(Vuex) // 2.建立對象 const store = new Vuex.Store({ state: { count: 0, persons: [ {name: 'a', age: 12}, {name: 'b', age: 23}, {name: 'c', age: 32}, {name: 'd', age: 24} ], person: { name: 'g', age: 100 } }, mutations, actions, getters, modules: { a: module_a } }) // 3.導出store對象 export default store
export default new Vuex.Store({ state:sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')): { enterprise: {}, grid: [], iofficeUserRoleID: '', userVO: {}, },
mounted() { window.addEventListener('unload', this.saveState) }, methods: { saveState() { sessionStorage.setItem('state', JSON.stringify(this.$store.state)) } }
import axios from 'axios' axios.defaults.baseURL = 'https://httpbin.org' axios.defaults.timeout = 5000 axios({ // url:'http://123.207.32.32:8080/home/mutidata', url: 'post', method: 'post', // 拼接在URL後 params: { name: 1 }, // 請求體中的參數 data: { type: 'sell', page: 3 }, //攔截請求 transformRequest:[function (query) { }], //攔截返回數據 transformResponse:[function (response) { }], }).then(res => { console.log(res); }) // 同時處理多個異步請求,最後返回一個數據數組,像java的柵欄 axios.all([axios({url: 'post', method: 'post'}), axios({url: 'get'})]).then(res => { console.log(res); }) //處理返回的結果數組,使用的是數組的解構是根據下標解構的 axios.all([axios({url: 'post', method: 'post'}), axios({url: 'get'})]) .then(([res1, res2]) => { console.log(res1); console.log(res2); }) // 這樣也能夠 axios.all([axios({url: 'post', method: 'post'}), axios({url: 'get'})]) .then( axios.spread((res1, res2) => { console.log(res1); console.log(res2); }))
避免使用全局的axios,可能每一個模塊的請求是不同的
新建/network/request.js
import axios from "axios"; export function request(config) { if (!config.baseURL) { config.baseURL = 'https://httpbin.org' } if (!config.timeout) { config.timeout = 5000; } const axiosInstance = axios.create(config); //req是請求參數對象 axiosInstance.interceptors.request.use(req => { console.log(req); //1.能夠修改一些請求的參數 // 2.能夠設置一個加載圖片 return req }) //res是返回的對象 axiosInstance.interceptors.response.use(res => { console.log(res.data); return res.data }) return axiosInstance(config); }
只會取當前模塊的引用
只會做用當前的組件的css
false
以阻止 vue 在啓動時生成生產提示。:style 後面是對象的時候裏面的屬性值是字符串格式
controller
@RequestMapping("save") public ResponseModel savenew(@RequestBody @Validated SysUser user, BindingResult result) { if (result.hasErrors()) { return ResponseModel.FAIL() .setMsg(result.getAllErrors() .stream() .map(err->err.getDefaultMessage()) .collect(Collectors.joining(";")) ); } String password = user.getPassword(); if (password.length() < 32) { user.setPassword(CryptUtil.shiroEncry(user)); } userService.save(user); return ResponseModel.SUCCESS(); }
vue
<template> <div id="user"> <div> 姓名: <input type="text" name="username" v-model="entity.username"/> </div> <div> 密碼: <input type="password" v-model="entity.password" /> </div> <div> 電話: <input type="text" v-model="entity.phone" /> </div> <div> 電話: <input type="text" v-model="entity.role.roleName" /> </div> <button @click="saveUserInfo">保存</button> </div> </template> <script> import { saveUser } from 'network/module/user.js'; export default { name: "User", methods: { saveUserInfo() { saveUser(this.entity).then(res=>alert(res.msg)); } }, data(){ return { entity:{ role:{} } } } }; </script>
前端工具請求接口的類型和後端服務器定義的類型不一致形成
vue.config.js
//vue-cli3配置這個作代理 devServer: { proxy: { '/api': { target: 'http://localhost:8080/mall/api', //API服務器的地址 changeOrigin: true, // 是否跨域 pathRewrite: { '^/api': '' } } }, }, //vue-cli2使用這個 // dev: { // proxyTable: { // '/api': { // target: 'http://localhost:8080/mall/api', //API服務器的地址 // changeOrigin: true, // 是否跨域 // pathRewrite: { // '^/api': '' // } // } // } // },
手寫嵌套對象:
{ a:{ 'b.c':d } }
qs默認嵌套對象的序列化會用 ‘[]’
//{ allowDots: true }會將【】轉換成 ‘.’ this.$qs.stringify(obj,{ allowDots: true })
~1.15.2 := >=1.15.2 <1.16.0 匹配到第二位,大於當前版本小於1.16.0
^3.3.4 := >=3.3.4 <4.0.0 匹配到第一位全部大於當前版本且小於4
this.$nextTick(function)將回調延遲到下次 DOM 更新循環以後執行,vm.$nextTick()
實例方法特別方便,由於它不須要全局 Vue
,而且回調函數中的 this
將自動綁定到當前的 Vue 實例上