创建脚手架流程:
- 创建一个基于webpack模板的新项目
// my-project 为自定义项目名
vue init webpack my-project
项目的名字不能大写,不然会报错
- yes no no no
- 安装依赖
cnpm install
- 运行项目
cnpm run dev
了解脚手架的基本内容:
- build文件夹及目录
webpack的配置,主要用于打包时的一些设置
- config文件以及子目录
整个项目开发运行时的一些配置
npm run dev时项目的启动端口等等
- node_modules文件以及子目录
node 的基础依赖包
- src文件以及子目录
- assets文件夹:放置资源文件(js,css......)
- components文件夹:组件的全部文件
组件!(一个vue项目是由一个个vue组件拼接起来的) - router文件:整个vue项目的路由,vue时单页面应用的代表,配置每个组件的地址文件夹
- app文件:整个文件的入口文件,相当与包裹整个页面的最外层的div
- main.js 文件:项目的主js,全局的使用各种变量、js、插件 在这里定义,引入
- static 文件夹以及子目录:
静态资源文件
- index 文件:
项目的承载页面
- package 文件:
整个项目所用到的插件的json的格式
脚手架的运行流程:
-
程序的入口
build文件夹下的webpack.base.conf.js文件:指定了整个文件配置成功后,在去执行的入口文件是src文件下的main.js文件 - main.js文件:构建的是vue实例(针对的是:index.html(该文件只提供了挂载容器)(脚手架都是基于单页面开发,所以会有唯一的html文件(index.html)))
- main.js进行渲染组件:App.vue(唯一的根组件是App.vue)
- App.vue组件:
- template:组件的内容+路由出口
router文件下的index.js:整个脚手架的配置项
1 程序的入口
首先,项目通过webpack进行打包,需要配置一个入口文件
在脚手架工程中,入口文件的配置文件位于build/webpack.base.conf.js
(webpack.base.conf.js为dev和prod配置文件公用配置,分别在dev和prod配置中被导入)
入口文件指向了src/main.js,(webpack对项目的打包入口为main.js)
import Vue from 'vue' // 导入vue
import App from './App' // 导入根组件
import router from './router' // 导入路由
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
可以看到,在入口文件main.js中,引入了Vue,根组件App,和路由插件router
并在初始化Vue实例时,配置挂载到#app,注册router插件,使用App根组件
挂载的#app位于项目跟目录的index.html中
2 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>hello-vue</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
表面上,index.html是一个空的html文档,仅提供了一个挂载点
实际并不是这样,这个index.html是作为一个模板存在的,
这里涉及到webpack的插件HtmlWebpackPlugin
回到webpack配置build/webpack.dev.conf.js
HtmlWebpackPlugin插件能根据模板生成html,并为生成的html页面添加静态资源引用script标签
所以我们看到的index.html并没有引用webpack打包后的静态资源文件
3,根组件App
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
.vue单文件组件文件分为三个部分:
template: 组件的模板Html 可使用是写html的形式声明组件模板,不再需要拼接字符串
script: 组件的js代码
style: 组件的CSS样式 可添加scoped属性,使CSS只对当前组件有效
根组件也是由template,script,style组成
template中使用了<router-view/>用于路由页面切换(SPA单页面应用)
路由配置在src/router/index.js中
4,路由配置src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
src/router/index.js最终导出了一个配置了路由的路由器实例
src/router/index.js在入口文件main中被引入,并在实例化vue时注入
由于默认路径/使用组件HelloWorld进行显示(<router-view/>)
所以访问http://localhost:8080/#/时,现实的视图是HelloWorld组件样式
案例:
- src/App.vue
<template>
<div id="app">
<!-- <img src="./assets/logo.png"> -->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
/* #app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} */
*{
margin: 0px;
padding: 0px;
}
- router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
// {
// path: '/',
// name: 'HelloWorld',
// component: HelloWorld
// }
{
path:'/',
name:'Home',
component:Home
}
]
})
- src/components/AddInfo.vue
<template>
<div>
<h3>TodoList管理</h3>
<div id="con">
<input type="text" v-model="item" id="input1" />
<button type="button" @click="addItem()" id="btn" >添加</button>
</div>
</div>
</template>
<script>
export default {
name: 'AddNew',
data () {
return {
item:''
}
},
methods:{
addItem(){
if(this.item==''){
alert("所输入信息不能为空");
}else{
this.$emit('submitItem',this.item);
this.item="";
}
}
}
}
</script>
<style scoped="scoped">
#con{
padding: 20px;
}
#input1{
width: 300px;
height: 30px;
outline: none;
font-size: 20px;
}
#btn{
width: 60px;
height: 34px;
border: none;
background-color: seagreen;
color: white;
outline: none;
}
</style>
- src/components/Home.vue
<template>
<div>
<AddNew @submitItem='addList' ></AddNew>
<h4>待完成任务列表</h4>
<InfoList @toDoneItem='doDone' :list="todoList" :type="false" ></InfoList>
<hr />
<InfoList @deleteItem='deleteInfo' :list="doneList" :type="true" ></InfoList>
</div>
</template>
<script>
import AddNew from '@/components/AddNew.vue';
import InfoList from '@/components/InfoList.vue';
export default {
name: 'Home',
data () {
return {
todoList:[],
doneList:[]
}
},
components:{
AddNew,
InfoList
},
methods:{
addList(item){
this.todoList.push(item);
},
doDone(index){
this.doneList.push(this.todoList.splice(index,1)[0]);
},
deleteInfo(index){
this.doneList.splice(index,1);
}
}
}
</script>
<style scoped="scoped">
</style>
- src/components/InfoList.vue
<template>
<div>
<ul>
<li v-for="(item,index) in list" :key="index" @click="setInfo(index)" >{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'InfoList',
data () {
return {
}
},
props:['list','type'],
methods:{
setInfo(index){
if(this.type){
this.$emit('deleteItem',index);
}else{
this.$emit('toDoneItem',index);
}
}
}
}
</script>
<style scoped="scoped">
ul{
margin-top: 15px;
}
li{
padding-left: 20px;
}
</style>
<style scoped="scoped">
ul{
margin-top: 15px;
}
li{
padding-left: 20px;
}
</style>