準(zhǔn)備工作
一、安裝腳手架
1、安裝vue腳手架,這是構(gòu)建vue項目的工具-g為全局安裝
? npm install -g vue-cli
2、使用webpack打包工具
? vue init webpack my-project
//之后會提示一些信息,全部選擇yes,一直敲回車即可
3、完成之后,進(jìn)入到創(chuàng)建的項目根目錄下
? cd my-project
4、安裝依賴包
? yarn
//說明:yarn是yarn install的簡寫,可直接敲擊yarn,功能和npm install一樣
5、最后運行項目
? yarn run dev
瀏覽器會自動打開運行一個頁面,出現(xiàn)以下頁面,說明成功了。
二、NPM
1、修改npm網(wǎng)址
淘寶 npm 網(wǎng)址
https://npm.taobao.org/
修改
npm config set registry http://registry.npm.taobao.org/
還原
npm config set registry https://registry.npmjs.org/
查看源
npm config get registry
// 或
npm config list
1234
修改源
# 默認(rèn)源
npm config set registry https://registry.npmjs.org
# https -> http,這樣網(wǎng)速就會好很多
npm config set registry http://registry.npmjs.org
# 如果還不能下載,就切換成淘寶源
npm config set registry https://registry.npm.taobao.org
npm install -g cnpm --registry=https://registry.npm.taobao.org
2、發(fā)布
1、手動創(chuàng)建 package.json或者npm init
{
"name": "mypridelife",
"version": "1.0.0",
"description": "npm of mypridelife",
"main": "a.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"mypridelife"
],
"author": "mypridelife",
"license": "ISC"
}
2、創(chuàng)建文件first.js
function hello(){
console.log("I am the most handsome man. ");
console.log("Do not accept any rebuttal. ");
}
exports.hello=hello;
3、發(fā)布
npm adduser
npm publish
4、使用
npm install mypridelife
5、創(chuàng)建測試文件test.js
var gyh = require("mypridelife");
gyh.hello();
6、運行
node test.js
三、yarn命令列表
常用命令:
創(chuàng)建項目:yarn init
安裝依賴包:yarn == yarn install
添加依賴包:yarn add
Yarn命令列表
| 命令 | 操作 | 參數(shù) | 標(biāo)簽 |
|---|---|---|---|
| yarn add | 添加依賴包 | 包名 | --dev/-D |
| yarn bin | 顯示yarn安裝目錄 | 無 | 無 |
| yarn cache | 顯示緩存 | 列出緩存包:ls,打出緩存目錄路徑:dir,清除緩存:clean
|
無 |
| yarn check | 檢查包 | ||
| yarn clean | 清理不需要的依賴文件 | ||
| yarn config | 配置 | 設(shè)置:set <key> <value>, 刪除:delete, 列出:list
|
[-g | --global] |
| yarn generate-lock-entry | 生成鎖定文件 | 無 | 無 |
| yarn global | 全局安裝依賴包 | yarn global <add/bin/ls/remove/upgrade> [--prefix] | --prefix 包路徑前綴 |
| yarn info | 顯示依賴包的信息 | 包名 | --json:json格式顯示結(jié)果 |
| yarn init | 互動式創(chuàng)建/更新package.json文件 | 無 | --yes/-y:以默認(rèn)值生成package.json文件 |
| yarn install | 安裝所有依賴包 | --flat:只安裝一個版本;--force:強(qiáng)制重新下載安裝;--har:輸出安裝時網(wǎng)絡(luò)性能日志;--no-lockfile:不生成yarn.lock文件;--production:生產(chǎn)模式安裝(不安裝devDependencies中的依賴) | |
| yarn licenses | 列出已安裝依賴包的證書 | ls:證書列表;generate-disclaimer:生成免責(zé)聲明 | |
| yarn link | 開發(fā)時鏈接依賴包,以便在其他項目中使用 | 包名 | |
| yarn login | 保存你的用戶名、郵箱 | ||
| yarn logout | 刪除你的用戶名、郵箱 | ||
| yarn list | 列出已安裝依賴包 | --depth=0:列表深度,從0開始 | |
| yarn outdated | 檢查過時的依賴包 | 包名 | |
| yarn owner | 管理擁有者 | ls/add/remove | |
| yarn pack | 給包的依賴打包 | --filename | |
| yarn publish | 將包發(fā)布到npm | --tag:版本標(biāo)簽;--access:公開(public)還是限制的(restricted) | |
| yarn remove | 卸載包,更新package.json和yarn.lock | 包名 | |
| yarn run | 運行package.json中預(yù)定義的腳本 | ||
| yarn self-update | yarn自身更新--未實現(xiàn) | ||
| yarn tag | 顯示包的標(biāo)簽 | add/rm/ls | |
| yarn team | 管理團(tuán)隊 | create/destroy/add/rm/ls | |
| yarn test | 測試 = yarn run test | ||
| yarn unlink | 取消鏈接依賴包 | ||
| yarn upgrade | 升級依賴包 | ||
| yarn version | 管理當(dāng)前項目的版本號 | --new-version :直接記錄版本號;--no-git-tag-version:不生成git標(biāo)簽 | |
| yarn why | 分析為什么需要安裝依賴包 | 包名/包目錄/包目錄中的文件名 |
四、NPM和Yarn命令對比
| npm 命令 | Yarn 命令 | 備注 |
|---|---|---|
| npm install | yarn install | 安裝所有依賴包(依據(jù)package.json中的依賴配置參數(shù)) |
| (N/A) | yarn install --flat | 單版本模式 |
| (N/A) | yarn install --har | 生成har文件,記錄安裝時網(wǎng)絡(luò)請求性能 |
| (N/A) | yarn install --no-lockfile | 不讀寫lockfile方式 |
| (N/A) | yarn install --pure-lockfile | 不生成yarn.lock文件 |
| npm install [package] | (N/A) | 安裝依賴 |
| npm install --save [package] | yarn add [package] | 添加生產(chǎn)模式依賴到項目 |
| npm install --save-dev [package] | yarn add [package][--dev/-D] | 添加開發(fā)模式的依賴 |
| (N/A) | yarn add [package][--peer/-P] | 對等模式添加依賴,發(fā)布/分享項目時的依賴 |
| npm install --save-optional [package] | yarn add [package] [--optional/-O] | 添加可選依賴包 |
| npm install --save-exact [package] | yarn add [package] [--exact/-E] | 精準(zhǔn)添加某版本的包 |
| (N/A) | yarn add [package] [--tilde/-T] | 添加同一次版本的包,如指定版本為1.2.3,可接受1.2.x的其他版本,但不接受1.3.x的版本 |
| npm install --global [package] | yarn global add [package] | 添加全局包 |
| npm rebuild | yarn install --force | 重建 |
| npm uninstall [package] | (N/A) | 刪除本地依賴包 |
| npm uninstall --save [package] | yarn remove [package] | 刪除正式依賴包 |
| npm uninstall --save-dev [package] | yarn remove [package] | 刪除開發(fā)依賴包 |
| npm uninstall --save-optional [package] | yarn remove [package] | 刪除可選依賴包 |
| npm cache clean | yarn cache clean | 清除緩存 |
| rm -rf node_modules && npm install | yarn upgrade | 更新包管理器自身 |
VUE
一、VUE基礎(chǔ)
1、標(biāo)簽
v-bind:title="message",
v-if="seen"
v-show是初始就加載
v-if 是“真正”的條件渲染,因為它會確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇讳N毀和重建。
v-if 也是惰性的:如果在初始渲染時條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r,才會開始渲染條件塊
v-for="todo in todos"
v-on:click="reverseMessage" v-on 縮寫 @
<input v-model="message">
v-bind:id="dynamicId" 縮寫 :
提升性能:v-pre
- 說明:vue會跳過這個元素和它的子元素的編譯過程??梢杂脕盹@示原始 Mustache 標(biāo)簽。跳過大量沒有指令的節(jié)點會加快編譯。
<span v-pre>{{ this will not be compiled }}</span>
提升性能:v-once
- 說明:vue只渲染元素和組件一次。隨后的重新渲染,元素/組件及其所有的子節(jié)點將被視為靜態(tài)內(nèi)容并跳過。這可以用于優(yōu)化更新性能。
<span v-once>This will never change: {{msg}}</span>
2、組件化與應(yīng)用構(gòu)建
import的名字!==下面components的名字==調(diào)用時候的標(biāo)簽名字,然后把import的源文件里的template里的div渲染給網(wǎng)頁。
文件名:MyComponent
路徑:../../components/MyComponent
導(dǎo)入:import MyComponent from '../../components/MyComponent'
聲明:components:{
my-components : MyComponent
}
使用:<my-components></my-components>
在一個大型應(yīng)用中,有必要將整個應(yīng)用程序劃分為組件,以使開發(fā)更易管理。在后續(xù)教程中我們將詳述組件,不過這里有一個 (假想的) 例子,以展示使用了組件的應(yīng)用模板是什么樣的:
<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>
3、數(shù)組更新機(jī)制
為了解決第一類問題,以下兩種方式都可以實現(xiàn)和 vm.items[indexOfItem] = newValue 相同的效果,同時也將觸發(fā)狀態(tài)更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
為了解決第二類問題,你可以使用 splice:
vm.items.splice(newLength)
4、對象更改檢測
Vue.set(vm.userProfile, 'age', 27)
5、組件怎么顯示
5.1、全局注冊
在腳手架創(chuàng)建的項目中,通過在main.js中聲明
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
然后在頁面app.vue中引用button-counter即可
這樣看起來更加清晰:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
5.2、局部注冊
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 選項中定義你想要使用的組件:
new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
5.3、Babel和webpack的模塊系統(tǒng)
然后你需要在局部注冊之前導(dǎo)入每個你想使用的組件。例如,在一個假設(shè)的ComponentB.js或ComponentB.vue文件中。
我們推薦創(chuàng)建一個 components 目錄,并將每個組件放置在其各自的文件中。
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
export default {
components: {
ComponentA,
ComponentC
},
// ...
}
}
import Vue from 'vue';
import MyComponent from '@/components/MyComponent.vue'; // 導(dǎo)入自己寫的組件文件
Vue.use(MyComponent); // 自定義全局組件的時候需要Vue.use();
Vue.component('my-component', MyComponent); //初始化組件
new Vue({
el: '#app',
router,
components: {
App,
MyComponent
},
template: '<App/>',
});
1、先寫組件
var tempalateDiv;
2、把組件寫進(jìn)一個對象里
var templateObject = {
props: ['product'],
template: tempalateDiv,
methods: {
increaseSales: function () {
this.product.sale = parseInt(this.product.sale);
this.product.sale += 1
this.$emit('increment')
}
}
}
3、生命全局組件
Vue.component('product', templateObject)
二、Vue.js 組件編碼規(guī)范
本規(guī)范提供了一種統(tǒng)一的編碼規(guī)范來編寫 Vue.js 代碼。這使得代碼具有如下的特性:
- 其它開發(fā)者或是團(tuán)隊成員更容易閱讀和理解。
- IDEs 更容易理解代碼,從而提供高亮、格式化等輔助功能
- 更容易使用現(xiàn)有的工具
- 更容易實現(xiàn)緩存以及代碼包的分拆
1、組件名稱用橫線-連接
<!-- 推薦 -->
<app-header></app-header>
<user-list></user-list>
<range-slider></range-slider>
<!-- 避免 -->
<btn-group></btn-group> <!-- 雖然簡短但是可讀性差. 使用 `button-group` 替代 -->
<ui-slider></ui-slider> <!-- ui 前綴太過于寬泛,在這里意義不明確 -->
<slider></slider> <!-- 與自定義元素規(guī)范不兼容 -->
2、組件結(jié)構(gòu)化
<template lang="html">
<div class="Ranger__Wrapper">
<!-- ... -->
</div>
</template>
<script type="text/javascript">
export default {
// 不要忘記了 name 屬性
name: 'RangeSlider',
// 使用組件 mixins 共享通用功能
mixins: [],
// 組成新的組件
extends: {},
// 組件屬性、變量
props: {
bar: {}, // 按字母順序
foo: {},
fooBar: {},
},
// 變量
data() {},
computed: {},
// 使用其它組件
components: {},
// 方法
watch: {},
methods: {},
// 生命周期函數(shù)
beforeCreate() {},
mounted() {},
};
</script>
<style scoped>
.Ranger__Wrapper { /* ... */ }
</style>
3、子組件父組件
<div id="app">
//父組件
<my-component message="來自父組件的數(shù)據(jù)"></my-component>
</div>
<script>
//子組件
Vue.component('my-component',{
props:['message'],
template:`<div>{{message}}</div>`
})
var app=new Vue({
el:'#app'
})
</script>
4、謹(jǐn)慎使用 this.$refs
<!-- 推薦,并未使用 this.$refs -->
<range :max="max"
:min="min"
@current-value="currentValue"
:step="1"></range>
<!-- 使用 this.$refs 的適用情況-->
<modal ref="basicModal">
<h4>Basic Modal</h4>
<button class="primary" @click="$refs.basicModal.hide()">Close</button>
</modal>
<button @click="$refs.basicModal.open()">Open modal</button>
<!-- Modal component -->
<template>
<div v-show="active">
<!-- ... -->
</div>
</template>
<script>
export default {
// ...
data() {
return {
active: false,
};
},
methods: {
open() {
this.active = true;
},
hide() {
this.active = false;
},
},
// ...
};
</script>
<!-- 如果可通過 emited 來做則避免通過 this.$refs 直接訪問 -->
<template>
<range :max="max"
:min="min"
ref="range"
:step="1"></range>
</template>
<script>
export default {
// ...
methods: {
getRangeCurrentValue() {
return this.$refs.range.currentValue;
},
},
// ...
};
</script>
5、使用組件名作為樣式作用域空間
使用組件名作為樣式命名的前綴,可基于 BEM 或 OOCSS 范式。
同時給 style 標(biāo)簽加上 scoped 屬性。
加上 scoped 屬性編譯后會給組件的 class 自動加上唯一的前綴從而避免樣式的沖突。
<style scoped>
/* 推薦 */
.MyExample { }
.MyExample li { }
.MyExample__item { }
/* 避免 */
.My-Example { } /* 沒有用組件名或模塊名限制作用域, 不符合 BEM 規(guī)范 */
</style>
6、提供組件 API 文檔
在模塊目錄中添加 README.md 文件:
range-slider/
├── range-slider.vue
├── range-slider.less
└── README.md
在 README 文件中說明模塊的功能以及使用場景。對于 vue 組件來說,比較有用的描述是組件的自定義屬性即 API 的描述介紹。
README.md
功能
range slider 組件可通過拖動的方式來設(shè)置一個給定范圍內(nèi)的數(shù)值。
該模塊使用 noUiSlider 來實現(xiàn)跨瀏覽器和 touch 功能的支持。
如何使用
<range-slider> 支持如下的自定義屬性:
| attribute | type | description |
|---|---|---|
min |
Number | 可拖動的最小值. |
max |
Number | 可拖動的最大值. |
values |
Number[] optional | 包含最大值和最小值的數(shù)組. 如. values="[10, 20]". Defaults to [opts.min, opts.max]. |
step |
Number optional | 增加減小的數(shù)值單位,默認(rèn)為 1. |
on-slide |
Function optional | 用戶拖動開始按鈕或者結(jié)束按鈕時的回調(diào)函數(shù),函數(shù)接受 (values, HANDLE) 格式的參數(shù)。 如: on-slide={ updateInputs }, component.updateInputs = (values, HANDLE) => { const value = values[HANDLE]; }. |
on-end |
Function optional | 當(dāng)用戶停止拖動時觸發(fā)的回調(diào)函數(shù),函數(shù)接受 (values, HANDLE) 格式的參數(shù)。 |
如需要自定義 slider 的樣式可參考 noUiSlider 文檔
7、盡可能使用 mixins
為什么?
Mixins 封裝可重用的代碼,避免了重復(fù)。如果兩個組件共享有相同的功能,則可以使用 mixin。通過 mixin,你可以專注于單個組件的任務(wù)和抽象的通用代碼。這有助于更好地維護(hù)你的應(yīng)用程序。
怎么做?
假設(shè)你有一個移動端和桌面端的菜單組件,它們共享一些功能。我們可以抽象出這兩個組件的核心功能到一個 mixin 中,例如:
const MenuMixin = {
data () {
return {
language: 'EN'
}
},
methods: {
changeLanguage () {
if (this.language === 'DE') this.$set(this, 'language', 'EN')
if (this.language === 'EN') this.$set(this, 'language', 'DE')
}
}
}
export default MenuMixin
要使用 mixin,只需將其導(dǎo)入到兩個組件中(我只展示移動組件)。
<template>
<ul class="mobile">
<li @click="changeLanguage">Change language</li>
</ul>
</template>
<script>
import MenuMixin from './MenuMixin'
export default {
mixins: [MenuMixin]
}
</script>
8、組件選項的順序
組件選項應(yīng)該有統(tǒng)一的順序。
export default {
name: '',
mixins: [],
components: {},
props: {},
data() {},
computed: {},
watch: {},
created() {},
mounted() {},
destroyed() {},
methods: {}
};
9、ESLINT
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/name-property-casing": ["error", "PascalCase"],
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': [2, 'allow-null'],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}
三、前端路由與Vue-router
1、基本用法
- 在main.js里使用Vue.use()加載插件
- 創(chuàng)建一個數(shù)組來自定路由匹配列表
- 繼續(xù)在main.js中完成配置和路由實例
- 在根實例app.vue中添加一個路由視圖<router-view>來掛載所有的路由組件
1、在main.js里使用Vue.use()加載插件
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue'
Vue.use(VueRouter);
2、創(chuàng)建一個數(shù)組來自定路由匹配列表,每一個路由映射一個組件:
const Routers = [
{
path:'/index',
components:(resolve) => require(['./views/index.vue'],resolve)
},
{
path:'/about',
components:(resolve) => require(['./views/about.vue'],resolve)
},
{
path:'/user:id',
component:(resolve) => require(['./views/user.vue],resolve)
}
{
path:'*',
redirect:'/index'
}
]
//在路由列表里,可以再最后添加意向,當(dāng)訪問的路徑不存在時,重定向到首頁。
//通過this.$route.params.id獲取到id,然后進(jìn)行分發(fā)
3、繼續(xù)在main.js中完成配置和路由實例
const RouterConfig={
//使用HTML5的History路由模式
mode: 'history',
routers: Routers
};
const router = new VueRouter(RouterConfig);
new Vue({
el:'#app',
router:router,
render: h => {
return h(App)
}
})
4、在根實例app.vue中添加一個路由視圖
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default{
}
</script>
//運行網(wǎng)頁時,<router-view>會根據(jù)當(dāng)前路由動態(tài)渲染不同的頁面組件。網(wǎng)頁中一些公共部分,比如頂部的導(dǎo)航欄,側(cè)邊導(dǎo)航欄,底部的版權(quán)信息,這些也可以直接寫在app.vue中,與<router-view>同級。路由切換時,切換的時<router-view>掛載的組件,其他的內(nèi)容不會變化。
2、跳轉(zhuǎn)
方式1:
直接修改地址欄
方式2:
this.$router.push(‘路由地址’);
this.$router.replace(‘路由地址’);
this.$router.go(int);
router.push({ path: 'home' })
// 命名的路由
router.push({
name: 'user',
params: {
userId: 123
}
})
// 帶查詢參數(shù),變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
方式3:
<router-link to="路由地址" replace></router-link>
使用replace不會留下History記錄,不能用后退鍵返回上一個頁面
3、vue-router的高級用法
場景:如何修改spa項目的網(wǎng)頁標(biāo)題
比較理想的一個思路是,在頁面發(fā)生路由改變時,統(tǒng)一設(shè)置。vue-router提供了導(dǎo)航鉤子beforeEach和afterEach,他們會在路由即將改變前和改變后觸發(fā),所以設(shè)置標(biāo)題可以在beforeEach鉤子完成。
const Routers= [
{
path:'/index',
meta:{
title: '首頁'
},
component:(resolve) => require(['./views/index.vue'],resolve)
}
];
const router = new VueRouter(RouterConfig);
router.brforeEach((to,from,next) =>{
window.document.title = to.meta.title;
next();
}
);
導(dǎo)航鉤子有三個參數(shù):
to:即將進(jìn)入的目標(biāo)的路由對象
from:當(dāng)前導(dǎo)航即將要離開的路由對象
next:調(diào)用該方法后,才能進(jìn)入下一個鉤子
場景:返回上一個頁面,滾動條的位置
router.afterEach((to,from,next) => {
window.scrollTo(0,0);
})
場景三:檢驗登錄
router.beforeEach((to,from,next) => {
if('登陸了'){
next();
}else{
next('/login');
}
})
4、路由器懶加載
結(jié)合這兩者,這就是如何定義一個能夠被 Webpack 自動代碼分割的異步組件。
const Foo = () => import('./Foo.vue')
在路由配置中什么都不需要改變,只需要像往常一樣使用 Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
四、狀態(tài)管理與Vuex
場景:跨組件共享數(shù)據(jù)的需求
1、基本用法
基本用法同vue-router
數(shù)據(jù)保存在Vuex選項的state字段內(nèi)
const store = new Vuex.Store({
state:{
count:0
}
})
在任何組件內(nèi),可以直接通過$store.state.count讀取
Vuex 中的 mutation 也需要與使用 Vue 一樣遵守一些注意事項:
1.最好提前在你的 store 中初始化好所有所需屬性。
2.當(dāng)需要在對象上添加新屬性時,你應(yīng)該使用 Vue.set(obj, 'newProp', 123), 或者
以新對象替換老對象:state.obj = { ...state.obj, newProp: 123 }
一般會獨立開來(使用mutation-types.js存放mutation常量)如:
//mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// 我們可以使用 ES2015 風(fēng)格的計算屬性命名功能來使用一個常量作為函數(shù)名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
問題
1、修改mintui樣式
修改樣式的核心是:自己寫的樣式優(yōu)先級>第三方組件樣式。
以此為原則:1)使用!important提升優(yōu)先級 2)main.js映入第三方組件后面,引入自定義的樣式表,webpack打包后樣式會覆蓋。
找到頁面中的css進(jìn)行覆蓋。
內(nèi)容居左:
text-align:left
<div style="text-align:center">
<span>span的居中可以通過放置在div中,然后讓div text-align實現(xiàn)居中</span>
</div>
2、路由跳轉(zhuǎn)
https://blog.csdn.net/qq_15646957/article/details/78070862
1.Params
由于動態(tài)路由也是傳遞params的,所以在 this.$router.push() 方法中path不能和params一起使用,否則params將無效。需要用name來指定頁面。
2.Query
頁面通過path和query傳遞參數(shù),該實例中row為某行表格數(shù)據(jù)
在目標(biāo)頁面通過this.$route.query獲取參數(shù):
this.$route.query.row.xxx
3、異步問題
因為要等到頁面更新過之后才能執(zhí)行某些操作,所以用:
vm.$nextTick( [callback] )
示例:
new Vue({
// ...
methods: {
// ...
example: function () {
// 修改數(shù)據(jù)
this.message = 'changed'
// DOM 還沒有更新
this.$nextTick(function () {
// DOM 現(xiàn)在更新了
// `this` 綁定到當(dāng)前實例
this.doSomethingElse()
})
}
}
})
4、axios請求中
當(dāng)請求成功時,會執(zhí)行 .then,否則執(zhí)行 .catch
這兩個回調(diào)函數(shù)都有各自獨立的作用域,如果直接在里面訪問 this,無法訪問到 Vue 實例
這時只要添加一個 .bind(this) 就能解決這個問題
.then(function(res){
console.log(this.data)
}.bind(this))
5、局部修改第三方組件庫樣式
為什么需要穿透scoped?
scoped看起來很美,但是,在很多項目中,會出現(xiàn)這么一種情況,即:引用了第三方組件,需要在組件中局部修改第三方組件的樣式,而又不想去除scoped屬性造成組件之間的樣式污染。此時只能通過特殊的方式,穿透scoped。
<style scoped>
外層 >>> 第三方組件 {
樣式
}
#myCell >>> .van-cell__value {
color: #ff0000;
}
</style>
具體參考:https://www.cnblogs.com/karthuslorin/p/9038854.html
修改element樣式問題: 用ui組件總免不了需要對它做一些個性化定制的需求,所以我們就要覆蓋element的一些樣式。 首先我們要了解一下vue scoped是什么,很多人非常喜歡用scoped,媽媽再也不用擔(dān)心樣式?jīng)_突問題了,其實scoped也沒有很神秘的,它就是基于PostCss的,加了一個作用局的概念。
//編譯前
.example {
color: red;
}
//編譯后
.example[_v-f3f3eg9] {
color: red;
}
復(fù)制代碼
它和我們傳統(tǒng)的命名空間的方法避免css沖突沒有什么本質(zhì)性的區(qū)別。 現(xiàn)在我們來說說怎么覆蓋element-ui樣式。由于element-ui的樣式我們是在全局引入的,所以你想在某個view里面覆蓋它的樣式就不能加scoped,但你又想只覆蓋這個頁面的element樣式,你就可在它的父級加一個class,以用命名空間來解決問題。
.aritle-page{ //你的命名空間
.el-tag { //element-ui 元素
margin-right: 0px;
}
}
建議向樓主一樣專門建一個scss文件里專門自定義element-ui的各種樣式
6、vscode的eslint
{
"workbench.colorTheme": "One Dark Pro",
"editor.formatOnSave": true,
"editor.formatOnType": false,
"editor.minimap.enabled": false,
"vetur.format.defaultFormatter.html": "js-beautify-html",
"vsicons.dontShowNewVersionMessage": true,
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
{
"language": "vue",
"autoFix": true
},
"html",
"vue"
],
"prettier.eslintIntegration": true,
"workbench.iconTheme": "material-icon-theme",
"terminal.integrated.shell.windows": "C:\\\\Windows\\\\System32\\\\cmd.exe",
"eslint.run": "onSave"
}
7、屏幕適配
分辨率:1334pt x 750pt
指的是屏幕上垂直有1136個物理像素,水平有750個物理像素。
屏幕尺寸:4.7in
注意英寸是長度單位,不是面積單位。4.7英寸指的是屏幕對角線的長度,1英寸等于2.54cm。
屏幕像素密度:326ppi
指的是每英寸屏幕所擁有的像素數(shù),在顯示器中,dpi=ppi。dpi強(qiáng)調(diào)的是每英寸多少點。
同時,屏幕像素密度=分辨率/屏幕尺寸
然而,這段代碼其實也并不完美,在IE瀏覽器中,由于橫屏豎屏的切換會對其造成影響。
為了解決這個兼容性的問題,最后再加上一句,就有了現(xiàn)在的:
響應(yīng)式布局:
<meta name = "viewport" content = "width=device-width,initial-scale=1" >
media="(orientation:landscape) and (min-width:500px)"橫向
media="(max-width:500px)"
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" />
在這個里面主要有這幾個屬性:
width - viewport的寬度
height - viewport的高度
initial-scale - 初始的縮放比例
minimum-scale - 允許用戶縮放到的最小比例
maximum-scale - 允許用戶縮放到的最大比例
user-scalable - 用戶是否可以手動縮放
如果要禁止頁面縮放,只要把user-scalable 設(shè)置成no 就可以
8、滾動條
有時候我們需要頁面滾動條滾動到某一固定的位置,一般使用Window scrollTo()方法。
語法就是:scrollTo(xpos,ypos)
xpos:必需。要在窗口文檔顯示區(qū)左上角顯示的文檔的 x 坐標(biāo)。
ypos:必需。要在窗口文檔顯示區(qū)左上角顯示的文檔的 y 坐標(biāo)。
例如滾動內(nèi)容的坐標(biāo)位置100,500:
window.scrollTo(100,500);
Your Repositorie項目
一、頁面布局
1、邊距問題
-
首先在html里面設(shè)置全局
body { margin: 0px; padding: 0px; } 其次在App.vue里面設(shè)置
<div id="app">
<x-header :left-options="{showBack: false}">
<x-icon type="github" class="icon-style" />
{{ title }}
<a v-show="token" slot="right" @click="handleLogout">logout</a>
</x-header>
<box gap="10px 10px">
<router-view />
</box>
</div>
<style lang="less">
.icon-style {
width: 30px;
vertical-align: middle;
margin-right: 6px;
}
</style>
使用box設(shè)置<router-view />的頁面邊距
二、svg在vux中的使用
1、在vue項目中使用
在沒有其他組件庫的情況下,需要安裝第三方插件vue-svg-icon
步驟如下:
- 安裝第三方插件
npm i vue-svg-icon - 在入口文件main.js引入
import Vue from from 'vue'
import Icon from 'vue-svg-icon/Icon.vue' //引入
Vue.component('icon', Icon) //注冊
- 將下載好的svg資源放到src\assets\svg中
- 使用:
<icon name="example"></icon>
name的值為svg文件名
2、在vux組件庫中的使用
官方文檔鏈接:
https://doc.vux.li/zh-CN/components/x-icon.html
官方文檔說的不夠詳細(xì),具體使用如下:
- 將下載好的svg資源放在node_modules\vux\src\icons下
- 在組件中直接使用
<x-icon type="ios-arrow-up" class="icon-red"></x-icon>
type的值為svg文件名,class為你要自定義的樣式
三、alias
文件的引用
alias(在webpack配置文件里面改)
VUE-CLI 3
1、打開cmd,輸入vue ui
VUE實現(xiàn)局部刷新
利用Vue里面的provide+inject組合
-
首先需要修改App.vue
//App.vue <template> <div id="app"> <div> <router-view v-if="isRouterAlive" /> </div> </div> </template> <script> export default { name: 'App', provide() { return { reload: this.reload } }, data() { return { isRouterAlive: true } }, methods: { reload() { this.isRouterAlive = false this.$nextTick(() => { this.isRouterAlive = true }) } } } </script> -
其次到需要刷新的頁面進(jìn)行引用
使用inject導(dǎo)入引用reload
inject: ['reload'], this.reload()