准备开发环境

  • 安装最新版node.js
  • 使用npm安装@vue/cli命令行工具包
  • 安装git
  • 安装开发ide,如vscode,sublime text, atom,vim等
  • 安装浏览器,chrome,firefox等

安装vue命令:npm install -g @vue/cli

创建工程项目

vue create todo --default

项目结构解析

执行tree -L 1后得到如下结构

├── babel.config.js
├── node_modules
├── package.json
├── package-lock.json
├── public
|      ├── favicon.ico
|      └── index.html
├── README.md
└── src
     ├── App.vue
     ├── assets
     │   └── logo.png
     ├── components
     │   └── HelloWorld.vue
     └── main.js
  • public/index.html 这是浏览器加载的第一个文件
  • src/main.js 这个vue.js应用的配置js文件
  • src/App.vue 这是vue.js组件,包含html文档结构和js代码以及css文档样式
  • src/assets/logo.png assets文件夹是存放静态资源文件

运行开发工具

cd todo
npm run serve

# 运行结果如下:
App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.51.54:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

打开浏览器,在浏览器中输入地址http://localhost:8080/,即可访问vue.js应用

替换缺省文档

<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<script>
    import HelloWorld from "./components/HelloWorld.vue"
    export default {
    name: 'app',
    components: {
    HelloWorld
}
}

</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.vue文件内容替换为如下内容:

<template>
<div id="app">
<h4>
To Do List
</h4>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>

添加css框架

因为要安装的bootstrap依赖于jquery,所以需要先安装jquery,可以使用如下命令查看

npm jquery -v
# 安装jquery
npm install jquery

然后在src/main.js下引入jquery

npm install -g是全局安装,npm install 是在当前目录下的node_modules目录下安装

import $ from 'jquery'

同时因为bootstrap依赖于popper.js,所以需要安装popper.js

npm install popper

运行如下命令,安装bootstrap4.0.0到项目

npm install [email protected]

添加bootstrap到src/main.js文件中

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// 添加bootstrap框架
import "bootstrap/dist/css/bootstrap.min.css"

new Vue({
  render: h => h(App),
}).$mount('#app')

css框架非常多,包括bootstrap,这些框架依赖如jquery等js,对html文档进行样式修改, 如果想使用vue.js特定的框架,vuetify是个不错的选择,当然还有另外一个如:bootstrap-vue等

npm run serve报错处理

Module Error (from ./node_modules/eslint-loader/index.js) error ‘$’ is defined but never used no-unused-vars

这是因为安装eslint规范

npm install eslint

# 进入node_modules目录的.bin目录下,初始化eslint
cd node_modules/.bin/
eslint --init
# 设置选项,除选择vue.js外,其他都选择默认选项

# 最后,将node_modules目录.bin目录下的.eslintrc.js文件拷贝到项目根目录下
# window下
copy .eslintrc.js ..\..\

# linux下
cp .eslintrc.js ../../

# 启动服务即可
cd ../../
npm run serve
  • 解决方法1:在.eslintrc.js文件中添加如下代码:
"rules": {
	"generator-star-spacing": "off",
	"no-tabs":"off",
	"no-unused-vars":"off",
	"no-console":"off",
	"no-irregular-whitespace":"off",
	"no-debugger": "off"
},
  • 解决方法2:注释掉不使用的那行代码
  • 解决方法3:关闭eslint

对html元素添加样式

修改src/App.vue文件

<template>
<div id="app">
<!-- 这里添加样式 -->
<h4 class="bg-primary text-white text-center p-2">
To Do List
</h4>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>

重启项目

npm run serve

添加动态内容

在App.vue文件中添加展示数据

<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf"
        }
    },
};
</script>

展示list任务列表

利用v-for指令对任务列表数据进行循环输出展示

<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
    <div class="container-fluid p-4">
        <div class="row">
            <div class="col font-weight-bold">Task</div>
            <div class="col-2 font-weight-bold">Done</div>
        </div>
        <div class="row" v-for="t in tasks" v-bind:key="t.action">
            <div class="col">{{t.action}}</div>
            <div class="col-2">{{t.done}}</div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [{
                    action: "Buy Flowers",
                    done: false
                },
                {
                    action: "Get Shoes",
                    done: false
                },
                {
                    action: "Collect Tickets",
                    done: true
                },
                {
                    action: "Call Joe",
                    done: false
                }
            ]
        }
    },
};
</script>

v-bind:key指令为当前的元素绑定一个id

添加checkbox

<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
    <div class="container-fluid p-4">
        <div class="row">
            <div class="col font-weight-bold">Task</div>
            <div class="col-2 font-weight-bold">Done</div>
        </div>
        <div class="row" v-for="t in tasks" v-bind:key="t.action">
            <div class="col">{{ t.action }}</div>
            <div class="col-2">
                <!-- 这里添加checkbox -->
                <input type="checkbox" v-model="t.done" class="form-check-input" />
                {{ t.done }}
            </div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [{
                    action: "Buy Flowers",
                    done: false,
                },
                {
                    action: "Get Shoes",
                    done: false,
                },
                {
                    action: "Collect Tickets",
                    done: true,
                },
                {
                    action: "Call Joe",
                    done: false,
                },
            ],
        };
    },
};
</script>

v-model指令是用于绑定数据,当数据有变动时,会自动更新相应位置的变量值,当然,这个是双向数据同步, 当对应元素的值改变时,也会更新绑定变量的值

过滤已完成的任务

<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
    <div class="container-fluid p-4">
        <div class="row">
            <div class="col font-weight-bold">Task</div>
            <div class="col-2 font-weight-bold">Done</div>
        </div>
        <div class="row" v-for="t in filteredTasks" v-bind:key="t.action">
            <div class="col">{{ t.action }}</div>
            <div class="col-2 text-center">
                <input type="checkbox" v-model="t.done" class="form-check-input" />
                {{ t.done }}
            </div>
        </div>
        <div class="row bg-secondary py-2 mt-2 text-white">
            <div class="col text-center">
                <input type="checkbox" v-model="hideCompleted" class="form-check-input" />
                <label class="form-check-label font-weight-bold">
                    Hide completed tasks
                </label>
            </div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [{
                    action: "Buy Flowers",
                    done: false,
                },
                {
                    action: "Get Shoes",
                    done: false,
                },
                {
                    action: "Collect Tickets",
                    done: true,
                },
                {
                    action: "Call Joe",
                    done: false,
                },
            ],
            hideCompleted: true
        }
    },
    computed: {
        filteredTasks() {
            return this.hideCompleted ? this.tasks.filter(t => !t.done) : this.tasks
        }
    }
};
</script>
  • computed 是定义计算属性,可以在数据变动时重新计算属性值并返回结果

创建新任务

<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
    <div class="container-fluid p-4">
        <div class="row">
            <div class="col font-weight-bold">Task</div>
            <div class="col-2 font-weight-bold">Done</div>
        </div>
        <div class="row" v-for="t in filteredTasks" v-bind:key="t.action">
            <div class="col">{{ t.action }}</div>
            <div class="col-2 text-center">
                <input type="checkbox" v-model="t.done" class="form-check-input" />
                {{ t.done }}
            </div>
        </div>
        <div class="row py-2">
            <div class="col">
                <input v-model="newItemText" class="form-control" />
            </div>
            <div class="col-2">
                <button class="btn btn-primary" v-on:click="addNewTodo">Add</button>
            </div>
        </div>
        <div class="row bg-secondary py-2 mt-2 text-white">
            <div class="col text-center">
                <input type="checkbox" v-model="hideCompleted" class="form-check-input" />
                <label class="form-check-label font-weight-bold">
                    Hide completed tasks
                </label>
            </div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [{
                    action: "Buy Flowers",
                    done: false,
                },
                {
                    action: "Get Shoes",
                    done: false,
                },
                {
                    action: "Collect Tickets",
                    done: true,
                },
                {
                    action: "Call Joe",
                    done: false,
                },
            ],
            hideCompleted: true,
            newItemText: ""
        }
    },
    computed: {
        filteredTasks() {
            return this.hideCompleted ? this.tasks.filter(t => !t.done) : this.tasks
        }
    },
    methods: {
        addNewTodo() {
            this.tasks.push({
                action: this.newItemText,
                done: false
            });
            this.newItemText = "";
        }
    }
};
</script>
  • v-on:click 指令用于绑定点击事件
  • methods 用于定义js函数,可用于v-on指令绑定用

持久存储数据

在App.vue中使用localStorage

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [],
            hideCompleted: true,
            newItemText: ""
        }
    },
    computed: {
        filteredTasks() {
            return this.hideCompleted ? this.tasks.filter(t => !t.done) : this.tasks
        }
    },
    methods: {
        addNewTodo() {
            this.tasks.push({
                action: this.newItemText,
                done: false
            });
            // 使用localStorage持久存储数据
            localStorage.setItem("todos", JSON.stringify(this.tasks));
            this.newItemText = "";
        },
    },
    created() {
        // 从localStorage中获取数据
        let data = localStorage.getItem("todos");
        if (data != null) {
            this.tasks = JSON.parse(data);
        }
    },
};
</script>
  • created() 是vue应用生命周期的一个事件,在vue应用创建成功后触发,并执行其中的代码

当你添加新任务后,刷新浏览器将会重载之前保存的数据

添加点睛之笔

  • 添加删除任务功能
  • 在没有可做任务时展示一个信息
<template>
<div id="app">
    <h4 class="bg-primary text-white text-center p-2">
        {{ name }}'s To Do List
    </h4>
    <div class="container-fluid p-4">
        <!-- 展示信息 -->
        <div class="row" v-if="filteredTasks.length == 0">
            <div class="col text-center">
                <b>Nothing to do. Hurrah!</b>
            </div>
        </div>
        <template v-else>
            <div class="row">
                <div class="col font-weight-bold">Task</div>
                <div class="col-2 font-weight-bold">Done</div>
            </div>
            <div class="row" v-for="t in filteredTasks" v-bind:key="t.action">
                <div class="col">{{ t.action }}</div>
                <div class="col-2 text-center">
                    <input type="checkbox" v-model="t.done" class="form-check-input" />
                    {{ t.done }}
                </div>
            </div>
        </template>
        <div class="row py-2">
            <div class="col">
                <input v-model="newItemText" class="form-control" />
            </div>
            <div class="col-2">
                <button class="btn btn-primary" v-on:click="addNewTodo">Add</button>
            </div>
        </div>
        <div class="row bg-secondary py-2 mt-2 text-white">
            <div class="col text-center">
                <input type="checkbox" v-model="hideCompleted" class="form-check-input" />
                <label class="form-check-label font-weight-bold">
                    Hide completed tasks
                </label>
            </div>
            <div class="col text-center">
                <button class="btn btn-sm btn-warning" v-on:click="deleteCompleted">Delete Completed</button>
            </div>
        </div>
    </div>
</div>
</template>

<script>
export default {
    name: "app",
    data() {
        return {
            name: "realjf",
            tasks: [],
            hideCompleted: true,
            newItemText: ""
        }
    },
    computed: {
        filteredTasks() {
            return this.hideCompleted ? this.tasks.filter(t => !t.done) : this.tasks
        }
    },
    methods: {
        addNewTodo() {
            this.tasks.push({
                action: this.newItemText,
                done: false
            });
            // 使用localStorage持久存储数据
            this.storeData();

            this.newItemText = "";
        },
        storeData() {
            localStorage.setItem("todos", JSON.stringify(this.tasks));
        },
        // 添加删除功能
        deleteCompleted() {
            this.tasks = this.tasks.filter(t => !t.done);
            this.storeData();
        }
    },
    created() {
        // 从localStorage中获取数据
        let data = localStorage.getItem("todos");
        if (data != null) {
            this.tasks = JSON.parse(data);
        }
    },
};
</script>
  • v-if指令 是if的判断语句,后接判断条件,当然其结构还包括v-else,v-else-if等
  • template 模板标签,可以用于定义模板结构