步步向前之vue
疑難雜癥
vue改造多頁面應用配置注意問題(踩了神坑...)
首先修改webpack配置,文章很多,主要參考這篇鏈接vue多頁面開發
不想移步的童鞋來:
在util.js里面尾部直接加入
/* 這里是添加的部分 ---------------------------- 開始 */// glob是webpack安裝時依賴的一個第三方模塊,還模塊允許你使用 *等符號, 例如lib/*.js就是獲取lib文件夾下的所有js后綴名的文件var glob = require('glob')// 頁面模板var HtmlWebpackPlugin = require('html-webpack-plugin')// 取得相應的頁面路徑,因為之前的配置,所以是src文件夾下的pages文件夾var PAGE_PATH = path.resolve(__dirname, '../src/pages')// 用于做相應的merge處理var merge = require('webpack-merge')//多入口配置// 通過glob模塊讀取pages文件夾下的所有對應文件夾下的js后綴文件,如果該文件存在// 那么就作為入口處理exports.entries = function () {var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')var map = {}entryFiles.forEach((filePath) => {var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))map[filename] = filePath})return map}//多頁面輸出配置// 與上面的多頁面入口配置相同,讀取pages文件夾下的對應的html后綴文件,然后放入數組中exports.htmlPlugin = function () {let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')let arr = []entryHtml.forEach((filePath) => {let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))let conf = {// 模板來源template: filePath,// 文件名稱filename: filename + '.html',// 頁面模板需要加對應的js腳本,如果不加這行則每個頁面都會引入所有的js腳本chunks: ['manifest', 'vendor', filename],inject: true}if (process.env.NODE_ENV === 'production') {conf = merge(conf, {minify: {removeComments: true,collapseWhitespace: true,removeAttributeQuotes: true},chunksSortMode: 'dependency'})}arr.push(new HtmlWebpackPlugin(conf))})return arr}/* 這里是添加的部分 ---------------------------- 結束 */webpack.base.conf.js 文件
/* 修改部分 ---------------- 開始 */entry: utils.entries(),/* 修改部分 ---------------- 結束 */webpack.dev.conf.js 文件
/* 注釋這個區域的文件 ------------- 開始 */// new HtmlWebpackPlugin({// filename: 'index.html',// template: 'index.html',// inject: true// }),/* 注釋這個區域的文件 ------------- 結束 */new FriendlyErrorsPlugin()//**注意我在新版本生成的這里是保存static目錄的東西不用在意**new CopyWebpackPlugin([{from: path.resolve(__dirname, '../static'),to: config.dev.assetsSubDirectory,ignore: ['.*']}])/* 添加 .concat(utils.htmlPlugin()) ------------------ */].concat(utils.htmlPlugin())webpack.prod.conf.js 文件
/* 注釋這個區域的內容 ---------------------- 開始 */// new HtmlWebpackPlugin({// filename: config.build.index,// template: 'index.html',// inject: true,// minify: {// removeComments: true,// collapseWhitespace: true,// removeAttributeQuotes: true// // more options:// // https://github.com/kangax/html-minifier#options-quick-reference// },// // necessary to consistently work with multiple chunks via CommonsChunkPlugin// chunksSortMode: 'dependency'// }),/* 注釋這個區域的內容 ---------------------- 結束 */// copy custom static assetsnew CopyWebpackPlugin([{from: path.resolve(__dirname, '../static'),to: config.build.assetsSubDirectory,ignore: ['.*']}])/* 該位置添加 .concat(utils.htmlPlugin()) ------------------- */].concat(utils.htmlPlugin())改造目錄
訪問方式
- http://localhost:8080/login.html
- http://localhost:8080/index.html
修改config目錄下的assetsPublicPath路徑的問題
相信很多人都查過npm run build后空白頁的問題然后修改assetsPublicPath的值/為./,然而這里改的話,所有頁面都會無法獲取,cannot get,此處困擾我三天,一度令我覺得自己不適合這行,適合喝西北風,本來就新手學vue,也沒什么資源,這里解決了,但build后的問題呢,未完待續,先調好開發效果,步步為營吧全局使用axios
-
結合 vue-axios使用
import axios from 'axios' import VueAxios from 'vue-axios'Vue.use(VueAxios,axios);getNewsList(){this.axios.get('api/getNewsList').then((response)=>{this.newsList=response.data.data;}).catch((response)=>{console.log(response);}) }, -
axios 改寫為 Vue 的原型屬性
首先在主入口文件main.js中引用,之后掛在vue的原型鏈上
import axios from 'axios'Vue.prototype.$ajax= axios在組件中使用
this.$ajax.get('api/getNewsList').then((response)=>{this.newsList=response.data.data;}).catch((response)=>{console.log(response);}) -
結合 Vuex的action
在vuex的倉庫文件store.js中引用,使用action添加方法
import Vue from 'Vue'import Vuex from 'vuex'import axios from 'axios'Vue.use(Vuex)const store = new Vuex.Store({// 定義狀態state: {user: {name: 'xiaoming'}},actions: {// 封裝一個 ajax 方法login (context) {axios({method: 'post',url: '/user',data: context.state.user})}}})export default store在組件中發送請求的時候,需要使用 this.$store.dispatch
methods: {submitForm () {this.$store.dispatch('login')}}
關于新版vue-cli安裝json-server在build文件里沒生成出dev-server文件
新版的vue-cli取消了dev-server.js和dev-client.js 改用webpack.dev.conf.js代替,所以 配置本地訪問在webpack.dev.conf.js里配置即可打開webpack.dev.conf.js,(在build目錄下),
在const portfinder = require(‘portfinder’)后添加以下兩行代碼
const appData = require('./db.json')//加載本地數據文件 const seller = appData.seller//獲取對應的本地數據,添加完以上代碼繼續在此文件里面向下查找devServer:{ }
在這個對象里添加配置,(不要刪除或覆蓋以前默認配置的值)
before(app) {app.get('/api/seller', (req, res) => {res.json({errno:0,data: seller})}) }, 每更改過webpack.dev.conf.js這個文件或者db.json文件,記得重新 npm run devexpress啟動數據服務模擬post請求
* `config`目錄下的`index.js`,修改`dev`中的`proxyTable`為: proxyTable: {'/api/': 'http://localhost:3000/'} * `build`目錄下`webpack.dev.conf.js`文件增加 // express配置servervar express = require('express')var apiServer = express()var bodyParser = require('body-parser')apiServer.use(bodyParser.urlencoded({ extended: true }))apiServer.use(bodyParser.json())var apiRouter = express.Router()var fs = require('fs')//apiName是你請求的方法/數據集合 不要動apiRouter.route('/:apiName') //接口路徑 .all(function (req, res) {fs.readFile('./data.json', 'utf8', function (err, data) { //讀取接口文件console.log(err)if (err) throw errvar data = JSON.parse(data)if (data[req.params.apiName]) {res.json(data[req.params.apiName])} else {res.send('no such api name')}})})apiServer.use('/api', apiRouter);apiServer.listen(3000, function (err) {if (err) {console.log(err)return}console.log('Listening at http://localhost:' + 3000 + '\n')}) * 修改build目錄下webpack.dev.conf.js文件中的devServer,增加:// Invalid Host header問題修復disableHostCheck: true 測試地址:`http://localhost:8080/apiPost/getNewsList` 這里的請求get和post都適用Vue中的圖片資源的引入
- css、template中的圖片靜態路徑可正常寫入,webpack可正常打包
-
js即放在script中的圖片路徑必須使用require引入,否則webpack打包時將無法識別這些資源,包括template中v-bind或:綁定的值,例如:
data () {return {slides: {src: require('../assets/slideShow/pic1.jpg'), //requiretitle: 'xxx1',href: 'detail/analysis'}}}
設置props默認值報錯
父子組件的值的傳遞在vue中很常用到,設置props的默認值時會遇到以下錯誤:
props: {selections: {type: Array,default: [{label: 'test',value: 0}]}}報錯: Props with type Object/Array must use a factory function to return the defaut value
翻譯過來就是 對象或數組的屬性默認值必須以一個工廠函數返回
也就是類似組件中data聲明一樣
以上屬性值應修改為:
props: {selections: {type: Array,default () {return [{label: 'test',value: 0}]}}}使用事件拋出一個值$event
有的時候用一個事件來拋出一個特定的值是非常有用的。例如我們可能想讓 <blog-post> 組件決定它的文本要放大多少。這時可以使用 $emit 的第二個參數來提供這個值:
<button v-on:click="$emit('enlarge-text', 0.1)">Enlarge text </button>然后當在父級組件監聽這個事件的時候,我們可以通過 $event 訪問到被拋出的這個值:
<blog-post...v-on:enlarge-text="postFontSize += $event" ></blog-post>或者,如果這個事件處理函數是一個方法:
<blog-post...v-on:enlarge-text="onEnlargeText" ></blog-post>那么這個值將會作為第一個參數傳入這個方法:
methods: {onEnlargeText: function (enlargeAmount) {this.postFontSize += enlargeAmount} }問題來了,當你需要在事件處理函數中既要傳入子組件拋出的值,又想再傳入其他參數呢?
<blog-post...v-on:enlarge-text="onEnlargeText(index, $event)"></blog-post>vue項目根目錄下index.html引入公共樣式如reset.css注意事項
index.html不能引入src里的文件,src里文件的會用webpack打包。webpack在開發時把static的文件復制到電腦內存里,打包時會復制到static目錄下,因此建議非要在頁面頭部引入的話可以放在static目錄下,或者可以選擇在main.js使用import導入例如:
<link rel="stylesheet" type="text/css" href="./static/reset.css">或者
// main.js import './common/style/reset.css'vue項目localhost可以訪問,IP地址替換后無法訪問的問題
vue生成的項目啟動地址默認在http://localhost:8080/#,但若將開發移動端則需在手機上測試效果,以前總是知道hbulider有本地外置服務器手機掃碼可以訪問項目,Vue則需修改根目錄下/config/index.js:
host: '0.0.0.0', // can be overwritten by process.env.HOST便可支持ip訪問地址,手機在同局域網下就可以預覽了
vue各個生命周期該干什么
- beforecreate : 可以在這加個loading事件
- created :在這結束loading,還做一些初始化,data已渲染,也可以在這里發送請求獲取頁面初始數據,實現函數自執行
- mounted : 在這發起axios請求,拿回數據,配合路由鉤子做一些事情
- beforeDestory: destoryed :當前組件已被刪除,清空相關內容
附生命周期圖:
Vue中使用less給元素添加背景圖片出現的問題
按照less官方文檔,url應當如下使用:
URLs // Variables @images: "../img";// Usage body {color: #444;background: url("@{images}/white-sand.png"); }故而有了根據屏幕分辨率設置背景圖片代碼
.bg-image(@url) {background-image: url('@{url}@2x.png');@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3){background-image: url('@{url}@3x.png');} } // 報錯報錯 找不到路徑的 這里要使用“~”符號來告訴less引號里面的內容不需要編譯。正確代碼:
.bg-image(@url) {background-image:~"url('@{url}@2x.png')";@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {background-image: ~"url('@{url}@3x.png')";} }如果組件里用使用計時器
// 在組件銷毀時(即切換組件或關閉頁面), // 調用destroyed方法清除計時器 destroyed(){clearTimeout(this.timer) }向子組件傳遞props值為Array或Object時的默認值設置
不能直接設置為[]或{},最好應設置為一個函數,比如:
{type: Object,default () {return {}}vue 偵聽器 watch 檢查 對象鍵值的變化
先來看官方教程對watch的示例應用:
watch: {firstName: function (val) {this.fullName = val + ' ' + this.lastName},lastName: function (val) {this.fullName = this.firstName + ' ' + val}}但是如果監聽的是data中的對象類型的值,直接用就不妥了。
受現代 JavaScript 的限制 (以及廢棄 Object.observe),Vue 不能檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實例時對屬性執行 getter/setter 轉化過程,所以屬性必須在 data 對象上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
這樣監聽了對象所有鍵值,性能開銷大,解決方案:用字符串
如下:
'sell.price': {handler(val) {console.log('TCL: handler -> val', val); //這里`val`是`sell.price`而不是`sell`}}未完待續
總結
- 上一篇: js实现简单的循环打字效果(思路分享)
- 下一篇: 康力优蓝发布新品:让AI教育从概念变成现