前言
这篇文章对纯新手友好,所以有过任何vue开发经验的人可以出门左转啦!这篇文章献给我的homie苏蕾儿童鞋,让她在学习vue项目的时候少走一点弯路(径直冲向末路哈哈哈)。
本文将会简单的介绍一下vue的生态环境以及其中涉及的思想。如果刚从原始的HTML+JS+CSS中转型,这篇文章可能会比较适合你。
我也是最近刚刚上手vue,之前有过一丢丢react开发经验,所以对于vue的整体思路有些许的了解。粗鄙之见也请各位大佬多多指教。
本文将会涉及如下内容:
- vue
- vue,vuex和vue-router的关系
- 为何需要vuex和vue-router
- vue-cli创建项目以及项目结构讲解
- 以官方提供的todolist作为初始项目讲解vue的基本语法,后面会陆续加入vuex和vue-router的使用
Vue
Vue语言有非常强的灵活性,可以直接在HTML页面中通过引入其js文件使用,也可以作为一个完整的项目使用。通常情况下,我们会将其作为一个完整的项目使用。这里我使用vue-cli新建一个基于webpack的vue项目。vue-cli创建项目的教程网上很多,这里就不详细解释了,可以看到新建完成后项目目录如下图所示:
在这个基础上我会再额外的新建两个文件夹views
,api
和store
,这篇文章暂时用不到api
和store
,之后引入vuex
之后会使用。
现在整体的项目目录如下:
现在着重解释一下其中几个目录和文件分别用来干啥。
先看根目录下的文件。
package.json
用来配置node环境,它会记录项目的相关信息以及该项目的依赖,有点像java的maven配置管理工具。通俗的来说,我们一个项目可能会用到很多外部依赖比如jquery。于是我们就需要一种科学有效的方式管理所有依赖及其对应的版本。而所有依赖都位于node_modules
文件夹中。后面我们使用npm工具进行依赖管理时还会提到他。
.gitignore
文件记录了git提交时不上传的内容,如node_modules
中的全部内容。
index.html
文件是项目的skeleton,我们来看一下它的内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>my website</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
这里除了将网页标题命名为我们的项目标题之外,还有一个id为app的div。所有的页面将以index.html作为大框架,将元素插入到div中。后面还会继续提及。
build
,config
文件夹涉及了各种配置文件,这里不赘述,因为我也不是很会webpack哈哈哈。
项目的核心代码都位于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;
}
</style>
它构建了一个名为App的模块。其实,这是整个项目的入口模块,所有的渲染都将会经过App模块,然后渲染至<div id="app"></div>
。因此可以在App.vue文件中定义整个项目最通用的结构比如Header,Sidebar等等。其它情况下也可以不对其进行任何修改。
components
文件夹和views
文件夹都用来存储模板,不同的是views文件夹中的内容对应一个完整的页面,而components中的内容对应各个可重用的元素。比如views对应一个用户个人信息界面,而components中可能包好这个界面中的Header,Sidebar,核心用户信息模块等等。
assets
中包含静态信息如图片等
router
目录之下index.js对应了vue-router的配置,涉及vue-router时会继续提及。
至此我们基本了解了vue项目中各个文件夹的作用。那么如何启动这个项目呢?这就需要我们的npm指令。
npm
npm的指令很多,核心的我们暂时只需要了解一下两种就可以了:npm install
: 安装依赖,比如我们需要安装jquery,就可以使用npm install jquery。在不指定版本号的情况下会下载最新版本npm run dev
: 运行开发配置下的项目,我们用这个指令在开发过程中启动项目并debug
进入代码
该todo来自于vue官网上,需要查看源码的可以去官网的github上下载。
首先我们需要使用npm install来安装项目现有的依赖,项目现有的依赖会从package.json文件夹中查看并下载。依赖下载的过程会比较慢,可以使用淘宝开发的cnpm。
我们在使用npm run dev
查看一下运行结果:
主要的组件都位于components
之下:
分别对应着新建Todo模块,单个Todo展示页面和Todo列表模块。因为这是一个单页面app,所有没有用到views来组装,而是直接在App.vue中进行组装。
<template>
<div id="app">
<h1 class="ui dividing centered header">Vue.js Todo App</h1>
<div class='ui three column centered grid'>
<div class='column'>
<todo-list v-bind:todos="todos"></todo-list>
<create-todo v-on:create-todo="createTodo"></create-todo>
</div>
</div>
</div>
</template>
<script>
import sweetalert from 'sweetalert';
import TodoList from './components/TodoList';
import CreateTodo from './components/CreateTodo';
export default {
name: 'app',
components: {
TodoList,
CreateTodo,
},
data() {
return {
todos: [{
title: 'Todo A',
project: 'Project A',
done: false,
}, {
title: 'Todo B',
project: 'Project B',
done: true,
}, {
title: 'Todo C',
project: 'Project C',
done: false,
}, {
title: 'Todo D',
project: 'Project D',
done: false,
}],
};
},
methods: {
createTodo(newTodo) {
this.todos.push(newTodo);
sweetalert('Success!', 'To-Do created!', 'success');
},
},
};
</script>
这里引入了TodoList和CreateTodo模板,并在<template>中使用。同时还用props传入了一组todo的数组模拟现有的todo内容。具体的vue语法这里将不涉及,可以去官网上学习,官网的教程可以说是非常新手友好了呢。
然后我们来看一看TodoList.vue
<template>
<div>
<p class="tasks">Completed Tasks: {{todos.filter(todo => {return todo.done === true}).length}}</p>
<p class="tasks">Pending Tasks: {{todos.filter(todo => {return todo.done === false}).length}}</p>
<todo v-on:delete-todo="deleteTodo" v-on:complete-todo="completeTodo" v-for="todo in todos" :todo.sync="todo"></todo>
</div>
</template>
<script type = "text/javascript" >
import sweetalert from 'sweetalert';
import Todo from './Todo';
export default {
props: ['todos'],
components: {
Todo,
},
methods: {
deleteTodo(todo) {
sweetalert({
title: 'Are you sure?',
text: 'This To-Do will be permanently deleted!',
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: 'Yes, delete it!',
closeOnConfirm: false,
},
() => {
const todoIndex = this.todos.indexOf(todo);
this.todos.splice(todoIndex, 1);
sweetalert('Deleted!', 'Your To-Do has been deleted.', 'success');
});
},
completeTodo(todo) {
const todoIndex = this.todos.indexOf(todo);
this.todos[todoIndex].done = true;
sweetalert('Success!', 'To-Do completed!', 'success');
},
},
};
</script>
<style scoped>
p.tasks {
text-align: center;
}
</style>
现在看Todo.vue文件。
<template>
<div class='ui centered card'>
<div class="content" v-show="!isEditing">
<div class='header'>
{{ todo.title }}
</div>
<div class='meta'>
{{ todo.project }}
</div>
<div class='extra content'>
<span class='right floated edit icon' v-on:click="showForm">
<i class='edit icon'></i>
</span>
<span class='right floated trash icon' v-on:click="deleteTodo(todo)">
<i class='trash icon'></i>
</span>
</div>
</div>
<div class="content" v-show="isEditing">
<div class='ui form'>
<div class='field'>
<label>Title</label>
<input type='text' v-model="todo.title" >
</div>
<div class='field'>
<label>Project</label>
<input type='text' v-model="todo.project" >
</div>
<div class='ui two button attached buttons'>
<button class='ui basic blue button' v-on:click="hideForm">
Close X
</button>
</div>
</div>
</div>
<div class='ui bottom attached green basic button' v-show="!isEditing &&todo.done" disabled>
Completed
</div>
<div class='ui bottom attached red basic button' v-on:click="completeTodo(todo)" v-show="!isEditing && !todo.done">
Pending
</div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['todo'],
data() {
return {
isEditing: false,
};
},
methods: {
completeTodo(todo) {
this.$emit('complete-todo', todo);
},
deleteTodo(todo) {
this.$emit('delete-todo', todo);
},
showForm() {
this.isEditing = true;
},
hideForm() {
this.isEditing = false;
},
},
};
</script>
它的<template>中包含了一个Todo块的信息。之后TargetList.vue用它来展示全部的Todo。
<template>
<div>
<p class="tasks">Completed Tasks: {{todos.filter(todo => {return todo.done === true}).length}}</p>
<p class="tasks">Pending Tasks: {{todos.filter(todo => {return todo.done === false}).length}}</p>
<todo v-on:delete-todo="deleteTodo" v-on:complete-todo="completeTodo" v-for="todo in todos" :todo.sync="todo"></todo>
</div>
</template>
<script type = "text/javascript" >
import sweetalert from 'sweetalert';
import Todo from './Todo';
export default {
props: ['todos'],
components: {
Todo,
},
methods: {
deleteTodo(todo) {
sweetalert({
title: 'Are you sure?',
text: 'This To-Do will be permanently deleted!',
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: 'Yes, delete it!',
closeOnConfirm: false,
},
() => {
const todoIndex = this.todos.indexOf(todo);
this.todos.splice(todoIndex, 1);
sweetalert('Deleted!', 'Your To-Do has been deleted.', 'success');
});
},
completeTodo(todo) {
const todoIndex = this.todos.indexOf(todo);
this.todos[todoIndex].done = true;
sweetalert('Success!', 'To-Do completed!', 'success');
},
},
};
</script>
<style scoped>
p.tasks {
text-align: center;
}
</style>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。