ToDo项目
参考
一、项目创建
- 新建文件夹 ToDo,进入文件夹 ToDo
- npm 初始化
# 命令会在当前目录线新建 package.json 文件
npm init
package.json 内容如下:
{
"name": "npminstal",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
- npm 安装依赖,
# 提示依赖其他包,则安装提示的包
npm i vue vue-loader vue-template-compiler css-loader style-loader
- 新建src文件夹,新建src/App.vue文件。内容如下:
<template>
<div id="app">hello {{name}}!</div>
</template>
<script>
export default {
data(){
return {
name:"world"
}
}
}
</script>
<style scoped>
#app{
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
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
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"]
}
]
},
plugins: [
new VueLoaderPlugin()
]
}
- 编辑 package.json, scripts属性增加build,如下:
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js"
},
...
- 测试构建
npm run build
二、配置css、image等
- css文件处理
step1、新建 src/assert目录,新建src/assert/stylus/app.css。内容如下
body{
color: green;
}
step 2、index.js文件中引入app.css
import Vue from 'vue'
import App from './App.vue'
import "./assert/stylus/app.css"
const root = document.createElement("div");
···
step3、安装style-loader css-loader。(第一章节已安装)
step4、配置webpack.config.js(第一章节已配置)
2. 图片处理
step1、新建 src/image目录,导入图片 leaf001.jpeg(图片名称)
step2、修改 src/stylus/app.css。修改后内容如下
body{
color: green;
background-image: url(../image/leaf001.jpeg)
}
step3、安装url-loader file-loader
npm i url-loader file-loader
step4、配置webpac.config.js
···
rules:[
{
test:/\.vue$/,
loader:"vue-loader"
},
···
{
test:/\.jpeg$/,
use:[
{
loader:"url-loader",
options:{
limit:1024,
//[name]:文件名 [ext]:文件扩展名
name:"prefix_[name].[ext]"
}
}
]
}
]
···
- stylus文件处理
step1、新建src/stylus/app.styl。内容如下:
body
font-size 40px
step2、index.js引入app.styl
import Vue from 'vue'
import App from './App.vue'
import "./assert/stylus/test.css"
import "./assert/image/leaf001.jpeg"
import "./assert/stylus/test.styl"
const root = document.createElement("div");
document.body.appendChild(root)
new Vue({
render:(h)=>h(App)
}).$mount(root)
step3、安装stylus stylus-loader
npm i stylus stylus-loader
step4、修改webpack.config.js,配置stylus-loader
···
rules:[
···
{
test:/\.styl$/,
use:["style-loader","css-loader","stylus-loader"]
}
]
···
三、配置weback-dev-server
- 安装webpack-dev-server cross-env
npm i webpack-dev-server cross-env
- 配置package.json。增加dev
···
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "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 VueLoaderPlugin = require('vue-loader/lib/plugin')
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"
},
···
]
},
plugins: [
new VueLoaderPlugin(),
new webpack.DefinePlugin({
"process.env":{
NODE_ENV:isDev?'"development"':'"production"'
}
}),
new HTMLPlugin()
]
}
if(isDev){
config.devtool = "#cheap-module-eval-source-map"
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
config.devServer={
host:"0.0.0.0",
port:9080,
overlay:{
error:true
},
hot:true
}
}
module.exports = config
- 启动webpack-dev-server
npm run dev
四、业务开发
-
删除无用代码
删除app.vue中个标签中的内容
删除index.js 中引入的全局样式 -
安装插件
npm i postcss-loader autoprefixer babel-loader babel-core
npm i babel-preset-env babel-plugin-transform-vue-jsx
- 新建 .babelrc。内容如下:
{
"presets": [
"env"
],
"plugins": [
"transform-vue-jsx"
]
}
- 新建postcss.config.js。内容如下:
const autoprefixer = require("autoprefixer")
module.exports={
plugins:[
autoprefixer()
]
}
- 配置 webpack.config.js。内容如下
···
{
test:/\.jsx$/,
loader:"babel-loader"
},
{
test:/\.styl$/,
use:[
"style-loader",
"css-loader",
{
loader:"postcss-loader",
options:{
sourceMap:true
}
}
]
}
···
- 界面
新建 src/ToDo文件夹。ToDo目录下新建
header.vue
<template>
<header class="main-header">
<h1>Todo</h1>
</header>
</template>
<script>
export default {
}
</script>
<style lang="stylus" scoped>
.main-header
text-align center
h1
font-size 100px
color rgba(175,47,47,0.4)
font-weight 400
margin 20px
</style>
footer.jsx
import "../assert/stylus/footer.styl"
export default {
data(){
return {
author:"XB"
}
},
render(){
return (
<div id="footer">
<span>Write by {this.author}</span>
</div>
)
}
}
todo.vue
<template>
<section class="real-app">
<input
type="text"
class="add-input"
placeholder="接下去要做什么"
autofocus="autofocus"
@keyup.enter="addTodo"
>
<Item :todo="todo"> </Item>
<Tabs :filter="filter"></Tabs>
</section>
</template>
<script>
import Item from "./item.vue"
import Tabs from "./tabs.vue"
export default {
data(){
return{
todo: {
id:1,
content:"学习",
completed:false
},
filter:"all"
}
},
components:{
Item,
Tabs
},
methods:{
addTodo(){
}
}
}
</script>
<style lang="stylus" scoped>
.real-app
width 600px
margin 0 auto
box-shadow 0 0 5px #666
.add-input
position relative
margin 0
width 100%
font-size 24px
font-family inherit
font-weight inherit
line-height 1.4em
border none
outline none
color inherit
box-sizing border-box
font-smoothing antialiased
padding 16px 16px 16px 36px
border none
box-shadow inset 0 -2px 1px rgba(0, 0, 0, 0.03)
</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
position relative
background-color #fff
font-size 24px
border-bottom 1px solid rgba(0,0,0,0.06)
&:hover
.destory:after
content 'x'
label
white-space pre-line
word-break break-all
padding 15px 60px 15px 15px
margin-left 45px
display block
line-height 1.2
transition color 0.4s
&.completed
label
color #d9d9d9
text-decoration line-through
.toggle
text-align center
width 50px
height 30px
position absolute
top 0
bottom 0
margin auto 0
border none
appearance none
outline none
&:after
content url('../assert/image/unChecked.svg')
&:checked:after
content url('../assert/image/checked.svg')
.destory
position absolute
top 0
right 10px
bottom 0
width 40px
height 40px
margin auto 0
font-size 30px
color #cc9a9a
margin-bottom 11px
transition color 0.2s ease-out
background-color transparent
appearance none
border-width 0
cursor pointer
outline none
</style>
tabs.vue
<template>
<div class="helper">
<span class="left">2 items left</span>
<span class="tabs">
<span
v-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
}
},
data(){
return {
states:["all","active","completed"]
}
},
methods:{
clearAllCompleted(){},
toggleFilter(){}
}
}
</script>
<style lang="stylus" scoped>
.helper
font-weight 100
display flex
justify-content space-between
padding 5px 0
line-height 30px
background-color #ffffff
font-size 14px
font-smoothing antialiased
.left, .clear, .tabs
padding 0 10px
.left .clear
width 150px
.left
text-align center
.clear
text-align right
cursor pointer
.tabs
width 200px
display flex
justify-content space-between
*
display inline-block
padding 0 10px
cursor pointer
border 1px solid rgba(175,47,47,0)
&.actived
border-color rgba(175,47,47,0.4)
border-radius 5px
</style>
- 业务
五、遇到的问题
- npm 安装警告
···
npm WARN vue-loader@15.7.1 requires a peer of css-loader@* but none is installed. You must install peer dependencies yourself.
···
问题分析:vue-loader依赖css-loader,需要手动安装css-loader
解决方案:
npm i css-loader
- npm run build 提示如下:
One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
- webpack-cli (https://github.com/webpack/webpack-cli)
The original webpack full-featured CLI.
We will use "npm" to install the CLI via "npm install -D".
Do you want to install 'webpack-cli' (yes/no):
输入:yes
- 解析.vue文件报 Module parse failed: Unexpected character ‘#’
ERROR in ./src/App.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
@ ./src/index.js 2:0-27 8:20-23
ERROR in ./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css& 16:0
Module parse failed: Unexpected character '#' (16:0)
问题分析:vue-loader 解析css样式失败
解决方案 :安装并配置style-loader css-loader,并配置webpack.config.js
step、安装loader
npm i style-loader css-loader
setp2、修改webpack.config.js
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
···
module:{
rules:[
{
test:/\.vue$/,
loader:"vue-loader"
},
{
test:/\.css$/,
use:["style-loader","css-loader"]
}
]
},
plugins: [
new VueLoaderPlugin()
]
}