文件:
目录
①拆分静态组件:组件要按照功能点拆分,命名不要与html冲突
②实现动态组件:考虑好数据存放位置,数据是一个组件在用,还是一些组件在用
一个组件用:放在组件自身即可
一些组件用:放在他们共同的父组件上(状态提升)
③实现交互:从绑定事件开始
父组件==》 子组件通信
子组件==》父组件通信(要求父先给子一个函数)
v-model绑定的值不能是props传过来的值,因为props是不可以修改的
修改对象中的属性时Vue不会报错,但是不推荐这样做
- // 该文件是整个项目的入口文件
-
- // 引入vue,这个vue不能解析template配置项
- import Vue from 'vue'
- // 下面这个是引入完整版的vue。这个vue能解析template配置项
- // import Vue from 'vue/dis/vue'
-
- // 引入APP组件,它是所有组件的父组件
- import App from './App.vue'
-
-
-
- // 关闭vue的生产提示
- Vue.config.productionTip = false
-
- // 创建vue实例对象---vm
- new Vue({
- el:'#app',
- render: h => h(App),
- })
- <div id="root">
- <div class="todo-container">
- <div class="todo-wrap">
-
-
- <MyHeader :addTodo="addTodo">MyHeader>
-
-
- <List
- :todos="todos"
- :checkTodo="checkTodo"
- :deleteTodo="deleteTodo"
-
- >List>
-
-
- <MyFooter
- :todos="todos"
- :checkAllTodo="checkAllTodo"
- :clearAllTodo="clearAllTodo"
- >MyFooter>
- div>
- div>
- div>
-
- <script>
- // 引入组件
- import MyFooter from './components/MyFooter.vue'
- import MyHeader from './components/MyHeader.vue'
- import List from './components/List.vue'
- import Item from './components/Item.vue'
-
-
-
-
- export default {
- name:'App',
- // 注册组件
- components:{
- MyFooter,
- MyHeader,
- List,
- Item,
- },
- data(){
- return{
- // done:true 这个地方不要加引号,否则会能跑,被误认为字符串
- todos:[
- {id:'001',title:'抽烟',done:true},
- {id:'003',title:'喝酒',done:false},
- {id:'002',title:'开车',done:true},
- ]
- }
- },
-
- methods:{
- // 添加一个todo
- addTodo(todoObj){
- this.todos.unshift(todoObj)
- },
- // 勾选or取消一个todo
- checkTodo(id){
- // 对上面的数据进行遍历
- this.todos.forEach( (todo)=>{
- if(todo.id === id){
- // 取反
- todo.done = !todo.done
- }
- })
- },
- // 删除一个todo
- deleteTodo(id){
- // 过滤器
- this.todos = this.todos.filter((todo)=>{
- // 将符合条件的留下
- return todo.id !== id
- })
- },
- // 底部复选框,将所有的todo都按照底部复选框的形式,(底部选就都选
- checkAllTodo(done){
- this.todos.forEach((todo)=>{
- todo.done = done
- })
- },
- // 清除所有已经完成的todo
- clearAllTodo(){
- this.todos = this.todos.filter((todo)=>{
- // 留下done为false的
- return !todo.done
- })
- }
- }
- }
- script>
-
- <style >
- /*base*/
- body {
- background: #fff;
- }
-
- .btn {
- display: inline-block;
- padding: 4px 12px;
- margin-bottom: 0;
- font-size: 14px;
- line-height: 20px;
- text-align: center;
- vertical-align: middle;
- cursor: pointer;
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- border-radius: 4px;
- }
-
- .btn-danger {
- color: #fff;
- background-color: #da4f49;
- border: 1px solid #bd362f;
- }
-
- .btn-danger:hover {
- color: #fff;
- background-color: #bd362f;
- }
-
- .btn:focus {
- outline: none;
- }
-
- .todo-container {
- width: 600px;
- margin: 0 auto;
- }
- .todo-container .todo-wrap {
- padding: 10px;
- border: 1px solid #ddd;
- border-radius: 5px;
- }
-
- style>
- <li>
-
- <label>
-
- <input type="checkbox" :checked="todo.done" @change="checkTodo(todo.id)"/>
- <span>{{todo.title}}span>
- label>
-
- <button class="btn btn-danger" @click="deleteTodo(todo.id)" >删除button>
- li>
- template>
-
- <script>
- export default {
- name:'Item',
-
- //接收List传过来的todo对象
- props:['todo','checkTodo','deleteTodo']
- }
- script>
-
- <style scoped>
- /*item*/
- li {
- list-style: none;
- height: 36px;
- line-height: 36px;
- padding: 0 5px;
- border-bottom: 1px solid #ddd;
- }
-
- li label {
- float: left;
- cursor: pointer;
- }
-
- li label li input {
- vertical-align: middle;
- margin-right: 6px;
- position: relative;
- top: -1px;
- }
-
- li button {
- float: right;
- /* 平时这个按钮不会显示出来 */
- display: none;
- margin-top: 3px;
- }
-
- li:before {
- content: initial;
- }
-
- li:last-child {
- border-bottom: none;
- }
-
- /* 可以使鼠标滑过前面紧贴元素目标1时,触发动态效果. */
- li:hover{
- background-color:#ddd ;
- }
-
- li:hover button{
- /* 成为“块级”元素 */
- display: block;
- }
- style>
- <div>
- <ul class="todo-main">
-
- <Item
- v-for="todoObj in todos"
- :key="todoObj.id"
- :todo="todoObj"
- :checkTodo="checkTodo"
- :deleteTodo="deleteTodo"
-
- >Item>
- ul>
- div>
-
- <script>
- import Item from './Item'
-
-
- export default {
- name:'List',
- components:{
- Item,
- },
- props:['todos','checkTodo','deleteTodo']
-
-
- }
- script>
-
- <style scoped>
-
- /*main*/
- .todo-main {
- margin-left: 0px;
- border: 1px solid #ddd;
- border-radius: 2px;
- padding: 0px;
- }
-
- .todo-empty {
- height: 40px;
- line-height: 40px;
- border: 1px solid #ddd;
- border-radius: 2px;
- padding-left: 5px;
- margin-top: 10px;
- }
- style>
-
- <div class="todo-footer" v-show="total">
- <label>
-
-
- <input type="checkbox" v-model="isAll"/>
- label>
- <span>
- <span>已完成{{doneTotal}}span> / 全部{{total}}
- span>
- <button class="btn btn-danger" @click="clearAll">清除已完成任务button>
- div>
-
-
- <script>
-
-
- export default {
- name:'MyFooter',
- props:['todos','checkAllTodo','clearAllTodo'],
- computed:{
- total(){
- return this.todos.length
- },
-
- // 下面是计算属性的简写形式(不用写成一个配置对象的形式)
- // 这个函数当成getter用,函数的名就是计算属性的名
- doneTotal(){
- // pre之前的值,current现在的值(在这个就是指的todo项
- return this.todos.reduce((pre,current)=>{
- // 这里面是一个函数,数组的长度是几,这个函数就调用几次
- return pre+(current.done ?1 : 0)
- },0)
- },
-
- // 判断一下,是不是下面的复选框跟着变
- isAll:{
- get(){
- return this.doneTotal===this.total && this.total>0
- },
- set(value){
- this.checkAllTodo(value)
- }
- }
-
- },
- methods:{
- // 全选或者全不选
- // checkAll(e){
- // this.checkAllTodo(e.target.checked)
- // }
- clearAll(){
- this.clearAllTodo()
- }
- }
- }
- script>
-
- <style scoped>
-
- /*footer*/
- .todo-footer {
- height: 40px;
- line-height: 40px;
- padding-left: 6px;
- margin-top: 5px;
- }
-
- .todo-footer label {
- display: inline-block;
- margin-right: 20px;
- cursor: pointer;
- }
-
- .todo-footer label input {
- position: relative;
- top: -1px;
- vertical-align: middle;
- margin-right: 5px;
- }
-
- .todo-footer button {
- float: right;
- margin-top: 5px;
- }
- style>
- <div class="todo-header">
- <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" />
- div>
-
- <script>
- // 使用id 的库
- import {nanoid} from 'nanoid'
-
- export default {
- name:'MyHeader',
- methods:{
- add(e){
- if(!e.target.value.trim()){
- // 如果是空的话,就执行下面的语句
- alert("输入不能为空")
- // 直接return
- return
- }
- const todoObj={id:nanoid(),title:e.target.value,done:false}
- this.addTodo(todoObj)
- // 当用户输入完成回车后,让文本框没有字符
- e.target.value=''
- }
-
- },
- props:['addTodo']
-
-
- }
- script>
-
- <style scoped>
- /*header*/
- .todo-header input {
- width: 560px;
- height: 28px;
- font-size: 14px;
- border: 1px solid #ccc;
- border-radius: 4px;
- padding: 4px 7px;
- }
-
- .todo-header input:focus {
- outline: none;
- border-color: rgba(82, 168, 236, 0.8);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- }
-
- style>