vue-cli 的依賴
html
vue-cli 的使用流程
vue
node 的安裝
node 是經過js 操做系統接口的語言; npm 是node的包管理工具;因此,安裝了node 就能夠直接使用npm 下載咱們須要的包;
node 能夠直接去node官網下載對應系統的安裝包,安裝提示完成;
而後在 命令行中 經過 npm -v 查看npm 版本,若是有出來表明安裝成功;node
npm 代理 到cnpm
你直接經過添加 npm 參數 alias 一個新命令:webpack
alias cnpm="npm --registry=https://registry.npm.taobao.org \ --cache=$HOME/.npm/.cache/cnpm \ --disturl=https://npm.taobao.org/dist \ --userconfig=$HOME/.cnpmrc"
而後運行es6
cnpm install xx -g //全局安裝xx
使用 vue-cliweb
vue init webpack demoName //生成 webpack 爲模板的vue項目
運行熱更新頁面ajax
npm run dev
生成項目能夠直接經過 http://localhost:8080/?#/ 訪問vue-router
若是你是拉別人的項目運行的,要先運行下面的命令,安裝依賴包vuex
npm install //或者 npm i
生成一個 靜態項目文件(直接打開的靜態頁面)vue-cli
npm run build
大多數狀況 ,生成的頁面是不能夠直接打開的;提示只能部署到 服務器上才能正常訪問;
若是須要直接本地打開;到項目目錄下的config文件夾裏的index.js文件中,將build對象下的assetsPublicPath中的「/」,改成「./」便可
生成的文件都是通過壓縮的,帶md5的文件
export default{} , module.exports = {}, exports { }
在node 的模塊中,exports 是 module.exports 的引用;可是在vue 中 不能寫成
exports = { porps:['text'] } // 提示 text 未定義;
exports default {} 定義的輸出;能夠經過 import xx 直接使用(標準ES6);寫法是:
exports default {a:123} import a;
module.exports = {} 與 exports default 是等價的
可是若是 同一個js 同時出現 module.exports ={} 和 import 就會報錯
module.exports = {a:123} //定義和導出 import a; //引入 //上面兩個關鍵詞 不能同時出如今同一個js 中
報錯緣由以下:
webpack可使用require和export ,可是不能混合使用import 和module.exports ,否則會報錯Cannot
assign to read only property 'exports' of object '#<Object>'
ES6 統一的寫法 是 import 和 exports default
若是你要import 組件 ;建議 統一使用 exports default {} 編寫組件
安裝
cnpm install vue-router
引入爲全局插件
能夠經過router-link 組件 連接到 對應組件;它會解析成相似a 標籤
<router-link :to="{path:'forms'}">forms</router-link> //注意書寫格式必定要正確 <router-link :to="{path:'father'}">father</router-link>
注意到 生成的url 中前面自動加了個 「#」;能夠經過添加 mode:'history', 去掉
原理:https://router.vuejs.org/zh-c...
路由配置中,path 能夠設置 url 帶參;
帶參path定義
表示 apple 後面跟的是參數,不是路徑;
帶參路徑
獲取參數
var router = new VueRouter() import browseMode from './components/browse-mode.vue' import blogList from './components/blog-list.vue' import blogArticle from './components/blog-article.vue' import writePanel from './components/write-panel.vue' router.map({ '/': { component: browseMode, subRoutes: { '/': { component: blogList }, '/details/:artId': { component: blogArticle } } }, '/edit/:mode': { component: writePanel }, '/search/tag/:tag': { component: browseMode, subRoutes: { '/': { component: blogList } } }, '/search/time/:time': { component: browseMode, subRoutes: { '/': { component: blogList } } }, '/search/title/:title': { component: browseMode, subRoutes: { '/': { component: blogList } } }, }) router.start(App, 'app')
<component v-bind:is="currentView"> var vm = new Vue({ el: '#example', data: { currentView: 'home' //改變這個值就會切換內容; }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
<li class="tab1"><router-link :to="{path:'box1/666'}">box1</router-link></li> // to的 值是一個對象 ,key 固定是path ,value 是 一個字符串; // 後面的666 是參數;它的前面不是 「 ?或者 & 」 而是 「 / 」;
<div>{{$route.params.text}}</div>
定義一個多參數 路由的 url
使用時的url多是這樣:
http://localhost:8080/#/apple/red/detail/fool //後面的detail 是固定的。
獲取的方法是同樣的;
var a = $route.params; //結果 a={ color:red, type:fool }
{ path:'/box1', component:box1, children:[ { // 當 /box1/box1a匹配成功, // box1a會被渲染在 box1的 <router-view> 中 path:'box1a', //這裏不加 「 / 」 component:box1a }, { path:'box1b', component:box1b } ] }, // 要注意,以 / 開頭的嵌套路徑會被看成根路徑。 這讓你充分的使用嵌套組件而無須設置嵌套的路徑。 //在box1 中定義一行 <router-view/> //子組件 box1a 會自動渲染 到頁面中; //若是添加兩個 router-link 組件 就能夠作tab切換(不建議用路由作tab) //router-link 只會切換 第一個父級的 router-view 中的內容,因此不會刷新整個 box1 ; <ul> <li class="tab1"><router-link :to="{path:'/box1/box1a'}">box1a</router-link></li> <li class="tab2"><router-link :to="{path:'/box1/box1b'}">box1b</router-link></li> </ul> //path 寫成 /box1/box1a 是用了根路徑(絕對路徑)的形式; //若是寫成 {path:'box1a'} 則是相對路徑;這樣寫點擊 瀏覽器的url會寫成 http://localhost:8080/box1a //由於頂級路由中是沒有定義 box1a 組件的;因此頁面空白;
帶參子路由
//路由定義 { path:'/box1/:text', component:box1, children:[ { path:'box1a', component:box1a }, { path:'box1b', component:box1b } ] }, //跳轉到 box1 的寫法 <li class="tab1"><router-link :to="{path:'box1/789'}">box1</router-link></li> //box1 中渲染 box1a/b 的寫法 <ul> <li class="tab1"><router-link :to="{path:url1}">box1a</router-link></li> <li class="tab2"><router-link :to="{path:url2}">box1b</router-link></li> </ul> //初始化的時候生成url mounted: function () { this.parms = this.$route.params.text; this.url1 = '/box1/'+this.parms+'/box1a' this.url2 = '/box1/'+this.parms+'/box1b' },
//路由定義 { path:'/box1/:text', component:box1, children:[ { path:'box1a', component:box1a }, { path:'box1b', component:box1b } ] }, //跳轉到 box1 的寫法 <li class="tab1"><router-link :to="{path:'box1/789'}">box1</router-link></li> //box1 中渲染 box1a/ b 的寫法 //to 屬性會自動 運算出來; <ul> <li class="tab1"><router-link :to="/box1/'+parms+'/box1a'">box1a</router-link></li> <li class="tab2"><router-link :to="'/box1/'+parms+'/box1b'">box1b</router-link></li> </ul> //初始化的時候生成url mounted: function () { this.parms = this.$route.params.text; },
具名路由
router-link 還能夠經過 name 指定跳轉(具名路由);經過例如 tag="li" 指定包裹標籤爲a覺得的tag;
children:[ { path:'box1a', name:"nameBox", component:box1a } ] <router-link :to="{name:'nameBox'}" tag="li">nameBox</router-link> //結果:會生成li, 點擊router-view 會渲染出 box1a ;注意,path是不可缺乏的
export default new Router({ mode:'history', routes: [ { path:'/index', components:{ //注意這裏是有 「 s 」 的 default:vuexIndex, //對應 <router-view/> left:vuexLeft, // 對應<router-view name="left"></router-view> right:vuexRight //對應<router-view name="right"></router-view> } } ] }) <template> <div id="app"> <router-view/> <div class="content"> <router-view name="left"></router-view> <router-view name="right"></router-view> </div> </div> </template> //注意訪問的路徑 是在components 中定義的path ;
{ path:'/layout', name:'layout', component:layout, children: [ { path: '/', components:{ default:main, leftView:leftView, topBar:topBar }, } ] }
路由的重定向
routes: [ { path:'/', redirect:'/box' //路徑不存在就跳轉到box }, { path: '/a', redirect: '/b' } //訪問a的路徑,都跳轉到b ]
當vue項目中 組件過多並設計到功能某些數據的時候,管理數據變得複雜,VUEX 就是經過自身的一套數據管理流程幫助你管理 項目數據(狀態);
安裝
cnpm install vuex --save
實例化
//在main.js 中 import Vuex from 'vuex' Vue.use(Vuex); let store = new Vuex.Store({ //Store 是vuex 方法 state:{ //存放變量的地方 total:0, appleTotal:0, bananaTotal:0, }, mutations:{ //定義同步變量的方法 aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } } }) new Vue({ el: '#app', store, //在實例中 引入 router, components: { App }, template: '<App/>' })
獲取值
vuex 的變量store 全局之後能夠經過如下語句獲取
this.$Store.state.total //組件中 <h3>總價:<span>{{$store.state.total}}</span></h3>
還能夠經過設置getter函數 暴露對應的值
getters:{ getTotal(state){ return state.total } }, //組件中 <h3>總價:<span>{{$store.getters.getTotal}}</span></h3>
經過在組件中調用如下特定語句改變
methods:{ add(){ this.cnt += 1; //bSetValue 是在vuex實例的mutations中定義的方法 //經過 bSetValue方法 去改變實例的值 this.$store.commit('bSetValue',this.cnt*5) }, minus(){ this.cnt-=1; this.$store.commit('bSetValue',this.cnt*5) } }, // 在vuex 中只有 commit 方法能夠改變數據;這裏是不建議直接在組件中調用 cmmit 的 // 由於cmmit中只能是同步操做;可是交互每每須要同步數據庫 // 更加好的方法是在 actions的方法 中觸發 commit;actions 方法支持異步操做; // 全部涉及 後端API 的接口都是放在actions 中進行
actions 屬性
mutations:{ aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } }, actions:{ // 定義doAfn 方法,間接觸發 aSetValue; // 在doAfn 方法是能夠用ajax 的 doAfn(context,price){ context.commit('aSetValue',price) }, doBfn(context,price){ context.commit('bSetValue',price) } }
組件中的觸發方式 經過 dispatch 觸發doAfn;
this.$store.dispatch('doAfn',val*10)
Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割:
官方文檔代碼
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的狀態 store.state.b // -> moduleB 的狀態
官方的文檔組織建議:
對於大型應用,咱們會但願把 Vuex 相關代碼分割到模塊中。下面是項目結構示例:
├── index.html ├── main.js ├── api │ └── ... # 抽取出API請求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 咱們組裝模塊並導出 store 的地方 ├── actions.js # 根級別的 action ├── mutations.js # 根級別的 mutation └── modules ├── cart.js # 購物車模塊 └── products.js # 產品模塊
https://vuex.vuejs.org/zh-cn/...
父組件
<template> <div class="left"> <h1>我是left</h1> <div class="tips">(我是{{text?text:'路由的方式'}}來的)</div> <div class="left-content"> <div class="item-box"> <apple/> <banana/> </div> <div class="price"> <h3>總價:<span>{{$store.getters.getTotal}}</span></h3> </div> </div> </div> </template> <script> import apple from '@/components/vuex/apple.vue' import banana from '@/components/vuex/banana.vue' export default { data: function () { return { } }, components:{ apple, banana }, props:['text'] } </script> <style scoped> h1{ text-align: center; } .left-content{ margin-top: 20px; } .item-box{ width: 48%; display: inline-block; } .price{ width: 50%; display: inline-block; vertical-align: bottom; } .item{ font-size: 15px; margin-top: 20px; margin-left: 20px; } </style>
apple 組件
<template> <div class="item"> <span>蘋果</span> <button @click="add">add</button> <button @click="minus">minus</button> <input v-model.number.lazy="cnt"> <span v-if="noEnough" class="red">庫存不夠</span> </div> </template> <script> module.exports = { data: function () { return { cnt:0, noEnough:false } }, methods:{ add(){ this.cnt += 1; }, minus(){ this.cnt-=1; } }, watch:{ cnt(val){ if(val>10){ this.noEnough = true; } if(val<0){ this.cnt=0 } if(val<10){ this.noEnough = false; } this.$store.dispatch('doAfn',val*10) } } } </script> <style scoped> .item input{ width: 40px; display: inline-block; } .red{ color:red; font-size: 12px; } </style>
banana 組件
<template> <div class="item"> <span>香蕉</span> <button @click="add">add</button> <button @click="minus">minus</button> <input v-model.number.lazy="cnt"> <span v-if="noEnough" class="red">庫存不夠</span> </div> </template> <script> module.exports = { data: function () { return { cnt:0, noEnough:false } }, methods:{ add(){ this.cnt += 1; }, minus(){ this.cnt-=1; } }, watch:{ cnt(val){ if(val>10){ this.noEnough = true; } if(val<10){ this.noEnough = false; } if(val<0){ this.cnt=0 } this.$store.dispatch('doBfn',val*5) } } } </script> <style scoped> .item input{ width: 40px; display: inline-block; } .red{ color:red; font-size: 12px; } </style>
main.js
// 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 Vuex from 'vuex' import App from './App' import router from './router' Vue.config.productionTip = false Vue.use(Vuex); let store = new Vuex.Store({ state:{ total:0, appleTotal:0, bananaTotal:0, }, getters:{ getTotal(state){ return state.total } }, mutations:{ aSetValue(state,value){ state.appleTotal = value state.total = state.appleTotal + state.bananaTotal; }, bSetValue(state,value){ state.bananaTotal = value state.total = state.appleTotal + state.bananaTotal; } }, actions:{ doAfn(context,price){ context.commit('aSetValue',price) }, doBfn(context,price){ context.commit('bSetValue',price) } } }) /* eslint-disable no-new */ new Vue({ el: '#app', store, router, components: { App }, template: '<App/>' })