步步向前之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实现简单的循环打字效果(思路分享)
- 下一篇: vue 路由传参 params 与 qu