Vue+Webpack打造todo应用
2019独角兽企业重金招聘Python工程师标准>>>
一、课程介绍
课程地址:https://www.imooc.com/learn/935
1.概要
2.vue-loader+webpack项目配置
安装vs-code和插件
EditorConfig for VS Code
ESLint
gitignore
language-stylus
Nunjucks
One Dark Pro
PostCSS syntax
Vetur
View In Browser
vscode-icons
软件配置
{"window.zoomLevel": 2,"editor.fontSize": 20,"workbench.iconTheme": "vscode-icons","files.autoSave": "onFocusChange","terminal.integrated.fontSize": 20,"editor.tabSize": 2
}
打开命令行:ctrl+~
初始化项目
npm init
安装
npm i webpack@^3.10.0 vue vue-loader@^13.6.0
注意:
A.webpack需要安装到4版本以下
B.vue-loader需要安装15版本以下(参考官方文档 https://vue-loader.vuejs.org/migrating.html#a-plugin-is-now-required . Vue-loader在15.*之后的版本都是 vue-loader的使用都是需要伴生 VueLoaderPlugin的)
安装警告依赖
npm i css-loader vue-template-compiler
初始化好了
新建src/app.vue
<template><div id="test">{{text}}</div>
</template>
<script>
export default {data(){return{text:'abc'}}
}
</script>
<style>
#test{color: red}
</style>
添加脚本
index.js
import Vue from 'vue'
import App from './app.vue'const root = document.createElement('div')document.body.appendChild(root)new Vue({render:(h) => h(App)
}).$mount(root)
webpack.config.js
"build": "webpack --config webpack.config.js"
执行打包命令
npm run build
生成dist文件夹
红色报错,说明没有编译器解释
npm run build
3. webpack配置项目加载各种静态资源及css预处理器
npm i style-loader url-loader file-loader
url-loader是建立在file-loader基础上的,base64,。
limit对文件大小做限制。
use不仅是读取,还包括做的一些处理。
[name]原文件名,[ext]扩展名
如运行还有其他报错,可参考上图给安装依赖版本
npm run build
新建styles/test-stylus.styl样式文件,写法很随意,可以不要大括号和冒号等
npm run build
需要安装stylus-loader
npm i stylus-loader stylus
4.webpack-dev-server的配置使用
安装
npm i webpack-dev-server@^2.9.7
这个版本应该与webpack版本相互兼容,3.1.5版本会报错,推测要在3以下
针对不同平台的依赖
npm i cross-env
说明:mac上不需要用set,windows上需要
配置好dev
引入html的插件
安装
npm i html-webpack-plugin
配置
使用插件,在js中可以直接引用环境判断,vue可以根据不同环境打包,开发环境会有很多错误提示,但是正式环境不需要
npm run dev
打开查看
设置热加载
package.js(部分)
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "cross-env NODE_ENV=production webpack --config webpack.config.js","dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"},
webpack.config.js
const path = require('path')const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')const isDev = process.env.NODE_ENV === 'development'const config = {target: 'web',entry:path.join(__dirname,'src/index.js'),output: {filename: 'bundle.js',path: path.join(__dirname, 'dist')},module: {rules: [{test: /\.vue$/,loader: 'vue-loader'},{test: /\.css$/,use: ['style-loader','css-loader']},{test: /\.styl/,use: ['style-loader','css-loader','stylus-loader']},{test: /\.(gif|jpg|jepg|png|svg)$/,use: [{loader: 'url-loader',options: {limit: 1024,name: '[name]-aaa.[ext]'}}]}]},plugins: [new webpack.DefinePlugin({'process.env': {NODE_ENV: isDev ? '"development"' : '"production"'}}),new HTMLPlugin()]
}if (isDev) {config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高config.devServer = {port: 8000,host: '0.0.0.0',overlay: {errors: true,},hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染// historyFallback: {// }// 入口地址映射,(略)// open: true //启动后自动打开页面},config.plugins.push(new webpack.HotModuleReplacementPlugin(),new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题)
}module.exports = config
二、vue2介绍和项目实践
1.vue2的核心知识介绍
2.配置vue的jsx写法以及postcss
安装插件
npm i postcss-loader autoprefixer babel-loader babel-core
项目文件夹下创建babelrc和postcss.config.js配置文件
postcss是在css文件都编译完之后,通过autoprefixer对其优化,需要加入浏览器前缀支持的
将vue-jsx文件的转化
npm i babel-preset-env babel-plugin-transform-vue-jsx
安装依赖
编译处理
更快一些
npm i babel-helper-vue-jsx-merge-props@^2.0.0 css-loader@^0.28.7 babel-plugin-syntax-jsx
npm run dev
打包没报错即可
3. 实现todo应用的界面
调整assets文件夹到src下
删除之前测试使用的
新建src/todo及其以下文件
新建assets/styles/globel.styl文件
引入
样式内容略,删除app.vue的内容
样式具体内容略。lang指定预处理器,scoped仅仅对本组件作用
(1)基本组件的引用,样式
header.vue
<template><header class="main-header"><h1>Todo</h1></header>
</template>
<style lang = 'stylus' scoped>
.main-header{text-align centerh1{font-size 100pxcolor rgba(175,47,47,0.6)font-weight 500margin 20px}
}
</style>
todo.vue
<template><section class="real-app"><input type="text"class="add-input"autofocus='autofocus'placeholder="接下来要做什么"@keyup.enter="addTodo"><item :todo='todo'></item><!-- @keyup 也就等于 v-on:keyup --><tabs :filter = 'filter'></tabs></section>
</template>
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
export default {data() {return{todo:{id:0,content:'this is todo',completed: false},filter:'all'}},methods: {addTodo(){}},components: {Item,Tabs}
}
</script>
<style lang=stylus scoped>
.real-app{width 70%min-width 500pxpadding 10pxbackground #ffffffcolor #555555margin 20px autobox-shadow 0 0 10px 5px rgba(0,0,0,0.5).add-input{width 84%font-size 24pxborder nonemargin 0 6%padding 20px 2%outline noneborder-bottom 1px solid #fff}.add-input:hover{color #333border-bottom 1px solid #ccccursor pointer}
}
</style>
tabs.vue
<template><div class="helper"><span class="left">2 items left</span><span class="tabs"><spanv-for="state in states":key="state":class="[state, filter === state ? 'actived' : '']"@click="toggleFilter(state)">{{state}}</span></span><span class="clear" @click="clearAllCompleted" type='button'>Clear Completed</span></div>
</template><script>
export default {props: {filter: {type: String,required: true}},data(){return{states:['all', 'active','completed']}},methods: {clearAllCompleted (){},toggleFilter(){}}
}
</script>
<style lang="stylus" scoped>
.helper{text-align center.left{width:18%;display inline-block}.tabs{width 50%display inline-blockmargin 10px autospan{min-width 33%display inline-block }span:hover{cursor pointercolor orange}span.actived{color red}}.clear{ width 30%display inline-block color:greyborder noneoutline none}.clear:hover{color blackcursor pointer}input[type='button']{border-width 0}
}
</style>
item.vue
<template><div :class="['todo-item',todo.completed ? 'completed' : '']"><input type="checkbox"class="toggle"v-model="todo.completed"><label>{{todo.content}}</label><button class="destory" @click="deleteTodo"></button></div>
</template>
<script>
export default {props:{todo:{type:Object,required:true}},methods:{deleteTodo(){}}
}
</script><style lang=stylus scoped>
.todo-item{vertical-align text-topborder nonepadding 15px 2%width 88%margin 10px 4%border-bottom 1px solid #eeefont-size 28pxinput[type="checkbox"],input[type="checkbox"]:checked{vertical-align text-topwidth 30pxheight 30px}.destory{width 30pxheight 30pxfloat right}
}
</style>
footer.jsx
import '../assets/styles/footer.styl'
export default {data() {return {author: 'Jhon'}},render(){return (<div id="footer"><span>written by {this.author}</span></div>)}
}
footer.styl
#footerbackground:rgba(0,0,0,0.2)text-align: centermargin-top: 50px
global.styl
bodybackground-image: url('../images/bg.jpg')
4.实现todo应用的业务逻辑
(1)添加和删除操作
父子组件通信
(2)数量统计,tab切换面板,clear清除所选item
至此代码:
tabs.vue
<template><div class="helper"><span class="left">{{unFinishedTodoLength}} items left</span><span class="tabs"><spanv-for="state in states":key="state":class="[state, filter === state ? 'actived' : '']"@click="toggleFilter(state)">{{state}}</span></span><span class="clear" @click="clearAllCompleted">Clear Completed</span></div>
</template><script>
export default {props: {filter: {type: String,required: true},todos: {type: Array,required: true}},data(){return{states:['all', 'active','completed']}},methods: {clearAllCompleted (){this.$emit('clearAllcompleted')},toggleFilter(state){this.$emit('toggle', state)}},computed: {unFinishedTodoLength(){return this.todos.filter(todo => !todo.completed).length}}
}
</script>
<style lang="stylus" scoped>
.helper{text-align center.left{width:18%;display inline-block}.tabs{width 50%display inline-blockmargin 10px autospan{min-width 33%display inline-block }span:hover{cursor pointercolor orange}span.actived{color red}}.clear{ width 30%display inline-block color:greyborder noneoutline none}.clear:hover{color blackcursor pointer}input[type='button']{border-width 0}
}
</style>
todo.vue
<template><section class="real-app"><input type="text"class="add-input"autofocus='autofocus'placeholder="接下来要做什么"@keyup.enter="addTodo"><item :todo='todo'v-for="todo in filterdTodos":key="todo.id"@del="deleteTodo"/><!-- @keyup 也就等于 v-on:keyup --><tabs :filter = 'filter' :todos="todos"@toggle='toggleFilter'@clearAllcompleted="clearAllcompleted"/></section>
</template>
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
let id = 0
export default {data() {return{todos:[],filter:'all'}},methods: {addTodo(e){this.todos.unshift({id: id++,content: e.target.value.trim(),completed: false})e.target.value =''},deleteTodo(id){this.todos.splice(this.todos.findIndex(todo => todo.id === id), 1)},toggleFilter(state){this.filter = state},clearAllcompleted(){this.todos = this.todos.filter(todo => !todo.completed)}},computed: {filterdTodos(){if (this.filter === 'all'){return this.todos}// 判断const completed = this.filter === 'completed'return this.todos.filter(todo => completed === todo.completed)}},components: {Item,Tabs}
}
</script>
<style lang=stylus scoped>
.real-app{width 70%min-width 500pxpadding 10pxbackground #ffffffcolor #555555margin 20px autobox-shadow 0 0 10px 5px rgba(0,0,0,0.5).add-input{width 84%font-size 24pxborder nonemargin 0 6%padding 20px 2%outline noneborder-bottom 1px solid #fff}.add-input:hover{color #333border-bottom 1px solid #ccccursor pointer}
}
</style>
item.vue
<template><div :class="['todo-item',todo.completed ? 'completed' : '']"><input type="checkbox"class="toggle"v-model="todo.completed"><label>{{todo.content}}</label><button class="destory" @click="deleteTodo"></button></div>
</template>
<script>
export default {props:{todo:{type:Object,required:true}},methods:{deleteTodo(){this.$emit('del', this.todo.id)}}
}
</script><style lang=stylus scoped>
.todo-item{vertical-align text-topborder nonepadding 15px 2%width 88%margin 10px 4%border-bottom 1px solid #eeefont-size 28pxinput[type="checkbox"],input[type="checkbox"]:checked{vertical-align text-topwidth 30pxheight 30px}.destory{width 30pxheight 30pxfloat right}
}
</style>
三、webpack配置优化
1. 配置css单独分离打包
npm i extract-text-webpack-plugin
添加引入,isDev判断为true,false,同时剪切module-rules-styl的编译
粘贴到dev时候的设置里
增加else里的判断,style-loader可以用fallback,打包后的速度更快
const path = require('path')const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const ExtractPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'const config = {target: 'web',entry:path.join(__dirname,'src/index.js'),output: {filename: 'bundle[hash:8].js',path: path.join(__dirname, 'dist')},module: {rules: [{test: /\.vue$/,loader: 'vue-loader'},{test: /\.jsx/,loader: 'babel-loader'},{test: /\.(gif|jpg|jepg|png|svg)$/,use: [{loader: 'url-loader',options: {limit: 1024,name: '[name]-aaa.[ext]'}}]}]},plugins: [new webpack.DefinePlugin({'process.env': {NODE_ENV: isDev ? '"development"' : '"production"'}}),new HTMLPlugin()]
}if (isDev) {config.module.rules.push({test: /\.styl/,use: ['style-loader','css-loader',{loader: 'postcss-loader',options: {sourceMap: true,}},'stylus-loader']})config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高config.devServer = {port: 8000,host: '0.0.0.0',overlay: {errors: true,},hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染// historyFallback: {// }// 入口地址映射,(略)// open: true //启动后自动打开页面},config.plugins.push(new webpack.HotModuleReplacementPlugin(),new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题)
} else{config.output.filename = '[name][chunkhash:8].js'config.module.rules.push({test: /\.styl/,use: ExtractPlugin.extract({fallback: 'style-loader',use: ['css-loader',{loader: 'postcss-loader',options: {sourceMap: true}},'stylus-loader']})} ),config.plugins.push(new ExtractPlugin('styles.[contentHash:8].css'))
}module.exports = config
npm run build
打包生成文件名
附带:package.json
{"name": "vue-ssr-tech","version": "1.0.0","description": "","main": "webpack.config.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "cross-env NODE_ENV=production webpack --config webpack.config.js","dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"},"author": "","license": "ISC","dependencies": {"autoprefixer": "^7.2.3","babel-core": "^6.26.3","babel-helper-vue-jsx-merge-props": "^2.0.0","babel-loader": "^7.1.2","babel-plugin-syntax-jsx": "^6.18.0","babel-plugin-transform-vue-jsx": "^3.7.0","babel-preset-env": "^1.7.0","cross-env": "^5.1.3","css-loader": "^0.28.7","extract-text-webpack-plugin": "^3.0.2","file-loader": "^1.1.11","html-webpack-plugin": "^3.2.0","postcss-loader": "^3.0.0","style-loader": "^0.22.1","stylus": "^0.54.5","stylus-loader": "^3.0.2","url-loader": "^1.0.1","vue": "^2.5.17","vue-loader": "^13.7.2","vue-template-compiler": "^2.5.17","webpack": "^3.10.0","webpack-dev-server": "^2.9.7"},"devDependencies": {}
}
如有版本报错,可根据上面替换安装
2.区分打包类库代码及hash优化
让浏览器加载更快
npm run build
hash和chunkhash区别:
chunkhash是每个模块一个hash,hash会有区别,而hash是整个应用一个hash
webpack.config.js
const path = require('path')const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const ExtractPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'const config = {target: 'web',entry:path.join(__dirname,'src/index.js'),output: {filename: 'bundle[hash:8].js',path: path.join(__dirname, 'dist')},module: {rules: [{test: /\.vue$/,loader: 'vue-loader'},{test: /\.jsx/,loader: 'babel-loader'},{test: /\.(gif|jpg|jepg|png|svg)$/,use: [{loader: 'url-loader',options: {limit: 1024,name: '[name]-aaa.[ext]'}}]}]},plugins: [new webpack.DefinePlugin({'process.env': {NODE_ENV: isDev ? '"development"' : '"production"'}}),new HTMLPlugin()]
}if (isDev) {config.module.rules.push({test: /\.styl/,use: ['style-loader','css-loader',{loader: 'postcss-loader',options: {sourceMap: true,}},'stylus-loader']})config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高config.devServer = {port: 8000,host: '0.0.0.0',overlay: {errors: true,},hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染// historyFallback: {// }// 入口地址映射,(略)// open: true //启动后自动打开页面},config.plugins.push(new webpack.HotModuleReplacementPlugin(),new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题)
} else{config.entry = {app: path.join(__dirname,'src/index.js'),vendor: ['vue']}// config.output.filename = '[name].[hash:8].js'config.output.filename = '[name].[chunkhash:8].js'config.module.rules.push({test: /\.styl/,use: ExtractPlugin.extract({fallback: 'style-loader',use: ['css-loader',{loader: 'postcss-loader',options: {sourceMap: true}},'stylus-loader']})} ),config.plugins.push(new ExtractPlugin('styles.[contentHash:8].css'),new webpack.optimize.CommonsChunkPlugin({name: 'verdor'}),// 在有新的模块加入的时候,webpack是会给新模块加入id的,插入顺序不同,倒是id会变化,使用浏览器的缓存就是去效果,这种方式可以规避。verdor要放在runtime前面new webpack.optimize.CommonsChunkPlugin({name: 'runtime'}))
}module.exports = config
四、总结
搭建项目-webpack构建(eg:vue-loader,jsx->babel,静态资源,缓存)
webpack中文网:https://www.webpackjs.com/
webapck官网(要翻墙):http://webpack.github.io/
配置很多
vue开发todo应用,.vue文件,数据传递,拆分组建,双向绑定,虚拟DOM,jsx文件-复杂场景(vue2)
错误解答
1.No parser and no filepath given
npm install vue-loader@^13.7.2
2.You may need an appropriate loader to handle this file type
解决:可能有些包的版本不合适,需要更改
转载于:https://my.oschina.net/u/3018050/blog/1924538
Vue+Webpack打造todo应用相关推荐
- Vue+Webpack打造todo应用(慕课学习笔记)
这门课在慕课网是免费的,但有部分包已被弃用需要用其他包代替,详细见官网.我还不想看官网,所以先放着吧. 关于模块打包的课程可以重刷 [仅个人记录,还不完整.暂时没有参考意义哦] 别人的项目源码.我的项 ...
- Vue.js 打造酷炫的可视化数据大屏
可视化技术与 Vue 介绍 实验介绍 在本节实验中,将对可视化技术的应用场景.发展历程进行介绍,让大家对可视化技术有一个基础的概念.随后将介绍如今流行的可视化框架与其之间的优缺点对比.最后介绍 Vue ...
- vue做混合式app_Vue Cordova教程-Vue+Cordova打造跨平台可安装的混合APP视频教程(大地)...
Vue+Cordova打造跨平台可安装的混合APP视频教程 必看说明: 目前购买此教程送Html5+Cordova+Ionic智能电视(TV)应用开发教程视频教程: 购买过Ionic的同学可以直接在( ...
- 用vue+webpack搭建的前端项目结构
上个项目第一次用到vue+webpack,也是我第一次尝试自动化.模块化的开发方式,总的来说就是结构太烂,开发体验差,效率低,难维护.细数的罪状有如下几条 没有servies层,全部ajax接口都和逻 ...
- Vue + webpack 项目实践
最近在内部项目中做了一些基于 vue + webpack 的尝试,在小范围和同事们探讨之后,还是蛮多同学认可和喜欢的,所以通过 blog 分享给更多人. 首先,我会先简单介绍一下 vue 和 webp ...
- vue 判断页面加载完成_在Vue+webpack中详细讲解基础配置
这篇文章主要介绍了Vue+webpack项目基础配置教程,需要的朋友可以参考下. 最近在学习webpack,跟着课程一个单页面应用,在这里记录一下. 这个部分主要讲了如何配置webpack的环境,以及 ...
- 从零构建vue+webpack (一)
写在前面: 给自己看,日常写业务有点儿繁琐,尝试着用vue+webpack 从零开始构建一个项目! 1.新建项目文件夹 运行命令 npm init (一路回车或者-y) 2.打开项目,新建src 文件 ...
- 踩坑之旅:springboot+vue+webpack项目实战(一)
2019独角兽企业重金招聘Python工程师标准>>> 网上关于springboot的小项目很多,node.js+vue的项目也很多,但是好像没有两者合一的项目,最近在想实践下将两者 ...
- [vue] webpack打包vue速度太慢怎么办?
[vue] webpack打包vue速度太慢怎么办? 升级webpack4,支持多进程 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主目录 与歌谣 ...
- [vue] 使用vue开发一个todo小应用,谈下你的思路
[vue] 使用vue开发一个todo小应用,谈下你的思路 结构: 输入部分( input )和输出部分( ul ) 逻辑:用户输入之后,通过事件触发拿到用户输入的数据存起来, 将用户数据集合通过 v ...
最新文章
- 数据结构(05)— 线性单链表实战
- php 多人游戏_「谁会是下一个王者农药」云服务器如何搭建游戏服务器?
- Unity Remote使用方法
- poj3279 Fliptile
- 求n个数中第k大的数_互联网高频面试题目:「回溯算法」求组合总和
- Arithmetic Sequence 三分,货仓选址,nth_element,__int128(济南)
- php limit限流,php+redis 限流
- seo建设者_SEO建设者,有哪些说不出的苦?
- 按钮设置成透明的方法
- php的修改数据库语句怎么写,php的数据库修改语句是什么
- java 安卓视频播放器_java - 学习做一个安卓视频播放器,有一些小问题!忘大家请教...
- 【Linux】【Services】【SaaS】Docker+kubernetes(11. 构建复杂的高可用网络)
- java 私有成员方法_Java Reflection 教程(7):类私有成员变量和方法
- 谷歌(Google Chrome)插件安装
- CCNA配置试验之八 帧中继——点到点子接口(point-to-point)的配置
- compute和compute by
- C#更新word目录
- 有一种友谊可以美的让人心颤——CHANDLER和JOEY 转贴 来自friends论坛
- sql中的类型转换---学习
- 电脑快捷键快速关机方法,电脑如何快速关机
热门文章
- atitit 未来学课程体系.docx
- Atitit 软件开发中的艾提拉思想与理念总结 后端优先 手机优先 做好政治动员 高层抽象 一定要出理论结果书籍总结 技术就是艺术 三个软件层次的划分 实现层 规划层 艺术层 无限生
- Atitit ftp概念与ftpclient 目录 1. Concept	1 1.1. Tftp(simple ftp) sftp ssh port22	1 1.2. ftp server
- Atitit java 原生 客户端 native desktop桌面 javafx 浏览器环境 导入jar jfxrt.jar 17M package com.attilax.ui;
- atitit 好的企业文化确实可能降低企业短期效率但是必须的.docx
- Atitit 游戏的原理与概论attilax总结
- paip.java swt 乱码问题解决
- paip.验证码识别---判断图片是否是彩色图片
- 朴灵:云计算的开发者视界中,OpenAPI 是绝对主角 | 凌云时刻
- 【情感识别】基于matlab GUI SVM语音情感识别(带面板)【含Matlab源码 876期】