Vue cli和todolist效果实现

cli

  1. cli是什么?
    cli是vue提供的一个快速(自动化) 构建项目的一个脚手架 ,类似于我们之前所学的 express-generator

  2. cli的版本
    目前最新 3.x
    老版本是 2.x

  3. cli的底层的自动化工具是: webpack

  4. cli的安装
    npm/cnpm/yarn 都可以使用

    1. $ yarn add @vue/cli global 这个是cli3的版本
      如果我们还想使用cli2的脚手架,那么我们可以在安装一个包
    2. $ yarn add @vue/cli-init global

    如果安装3失败了,
    那么你可以使用cnpm继续安装 @vue/cli @vue/cli-init
    1. $ cnpm i @vue/cli -g 这个是cli3的版本
    如果我们还想使用cli2的脚手架,那么我们可以在安装一个包
    1. $ cnpm i @vue/cli-init -g

    如果还有问题:
    那么你就不要使用cli3了,你可以单独安装cli2

     `$ cnpm i vue-cli -g`
    
  5. 验证是否安装成功
    命令行输入: $ vue 看是否有东西输出,如果输出命令提示,证明安装成功

  6. 创建项目

cli3版本创建
1. 命令创建 【 推荐 】
$ vue create project

    - 手动选择配置
    - 如果安装node-sass出问题,如何解决: 
      - 先切换成npm源   nrm use npm
      - 使用cnpm 安装  cnpm i node-sass sass-loader -D

2. 图形界面创建
    `$ vue ui`

cli2
1. 标准版
$ vue init webpack project

  • 目录介绍:
    - package.json 整个项目的依赖配置文件,脚本命令运行的存储文件
    - build 整个项目的配置性文件,比如webpack配置
    - config 对整个项目的静态服务器配置
    - dist 运行 npm build 打包出来的文件
    - js 项目的js文件
    - .map 文件 错误资源定制文件
    - html 整个项目的容器,也是根实例的模板
    - node_modules 整个项目的依赖包文件
    - src 源代码开发目录,也是开发者具体操作的目录
    - assets 开发环境的静态资源 , webpack编译
    - components 组件存放目录
    - xxx.vue 一个.vue文件就是一个组件,我们称之为:单文件组件(template js style)
    - App.vue 根实例的直接子组件,其他组件往App.vue中放
    - main.js 整个项目的入口文件
    - .babelrc 优雅降级
    - .editorconfig 编辑器配置文件
    - .gitignore 配置git上传时,不需要上传文件配置
    - postcssrc.js css预处理器的配置
    - display: flex;
    - -webkit
    - -moz
    - -ms
    • README.md 项目说明文件
      • static 生产环境的静态资源 webpack不编译
    1. 简易版
      $ vue init webpack-simple project

总结:
cli3 的 webpack 配置放在了node_modules 的 @vue/cli-server 中
cli2 的配置
standard build目录中
simple webpack.config.js

问题: 如果我们在cli3中要进行webpack配置,怎么办?
分析: cli3的基础webpack 配置我们不要动 , 将来node_modules会被删除
解决: 新建一个vue.config.js文件进行webpack的覆盖配置

.vue文件 – 单文件组件

  1. 包含部分
    .vue文件包含三个部分
    1. template 模板:DOM结构
    2. script 组件的配置项
    3. style 样式

注意:template是必须有的,script和style可以没有

单文件组件: 一个组件就是一个文件

.vue 文件命名要使用大驼峰 【推荐】 或是 - 的形式
举例:
Father
movie-box
ContentBox MovieBox

要想在编辑器中 .vue 文件代码高亮 , 安装Vetur插件

单文件组件使用:
1. 先创建.vue文件
2. 想在哪里使用就在哪里导入
import xxx from xxx
3. 在当前组件中注册导入的组件
export default {
components: {
xxx
}
}

【HMR】 热重载: 文件修改,浏览器自动刷新


<style scoped></style>
  scoped 将当前组件的样式设立独立作用域,只在当前组件中有效

AddInput.vue代码

<template>
  <div class="add-input">
    <input type="text" v-model = "val" 
      @keyup.enter = "addItem"
      @focus = "getFocus"
    >
  </div>
</template>

<script>
export default {
  data () {
    return {
      val: '请输入'
    }
  },
  props: ['add'],
  methods: {
    getFocus () {
      this.val = ''
    },
    addItem () {
      this.add( this.val )
      this.val = ''
      this.$emit('addflag')
    }
  }
}
</script>


<style scoped>
  .add-input{
    position: relative;
    left: 0;top: 44px;
    z-index: 1000000;
  }
</style>

Content.vue 代码

<template>
   <!-- content -- start -->
    <div class="content">
      <div 
        class="card"
        v-for = " (todo,index) in newtodos "
        :key = " todo.id "
      >
        <div class="card-content">
          <div class="card-content-inner" > {{ todo.task }} </div>
          <div class="my-btn-box pull-right">
            <button 
              class="button button-success"
              @click = " todo.flag = !todo.flag "
              :class = "[ todo.flag?'button-fill':'']"
            > 
              <i class="icon icon-check"></i>
            </button>

            <button 
              class="button button-danger"
              @click = 'checkItem( index )'
            > 
              <i class="icon icon-remove"></i>
            </button>

          </div>
        </div>
      </div>

    </div>
  <!-- content -- end -->
</template>

<script>
export default {
  props: ['newtodos'],
  methods: {
    removeItem ( index ) {
      this.$emit('remove',index)
    },
    checkItem ( index ){
      this.$emit('check',index)
    }
  }
}
</script>


Foot.vue代码

<template>
  <footer>
    <ul>
      <li
        v-for = "btn in btns "
        :key = "btn.id"
        class="circle"
        :class = "['circle-'+btn.mold,type === btn.name?'circle-fill':'']"
        @click = "change( btn.name )"
      >
        {{ btn.content }}
      </li>
    </ul>
  </footer>
</template>

<script>
export default {
  props: ['btns','type'],
  methods: {
    change ( val ) {
      this.$emit('changetype',val)
    }
  }
}
</script>

Head.vue代码

<template>
    <!-- header --  start -->
      <header class="bar bar-nav">
        <a class="icon icon-star pull-left"></a>
        <a class="icon icon-edit pull-right" @click = 'edit'></a>
        <h1 class="title"> Todo_List </h1>
      </header>
    <!-- header --  end -->
</template>

<script>
export default {
  methods: {
    edit () {
      this.$emit('edit')
    }
  }
}
</script>


LayOut.vue 代码

<template>
  <div class="page-group">
    <div class="page page-current">
      <Head @edit = "editChange"></Head>
      <add-input 
        v-if = "add_todo_flag" 
        :add = "addTodoItem"
        @addflag = "editChange"  
      ></add-input>
      <Content 
        :newtodos = 'newTodos'
        @remove = 'remove'  
        @check = 'check'
      ></Content>
      <mask-component 
        v-show = "mask_flag"
        @mask = "maskHandler"
        @remove = "remove"
        :active-index = 'active_index'
      ></mask-component>
      <Foot
        :btns = 'btns'
        :type = 'type'
        @changetype = 'changeType'
      ></Foot>
    </div>

  </div>
</template>

<script>
  import Head from './Head'
  import Content from './Content'
  import Foot from './Foot'
  import MaskComponent from './MaskComponent'
  import AddInput from './AddInput.vue'
  export default {
    components: {
      Head,Content,Foot,MaskComponent,AddInput // 大部分人都会忘记
    },
    data () {
      return {
        todos: [
          {
            id: 1,
            task: '做作业',
            flag: true
          },
          {
            id: 2,
            task: '打游戏',
            flag: true
          },
          {
            id: 3,
            task: '化妆',
            flag: true
          }
        ],
        add_todo_flag: false, //编辑按钮的开关
        add_todo_input: '请输入代办任务',// 这个数据就是编辑添加的 input 的value
        mask_flag: false, //遮罩层控制开关
        active_index: 0 ,//保存index,在mask点击确定按钮的时候使用
        btns: [
          {
            id: 1,
            content: 'A', // all  全部的任务
            name: 'all',
            mold: 'success' //类型
          },
          {
            id: 2,
            content: 'F', //finish  完成了的任务
            name: 'finish',
            mold: 'primary'
          },
          {
            id: 3,
            content: 'U', //unFinish 未完成的任务
            name: 'unfinish',
            mold: 'warning'
          }
        ],
        type: 'all'
      }
    },
    
  
  methods: {
    changeType ( type ) {
      this.type = type
    },
    maskHandler () {
      this.mask_flag = false
    },
    editChange() {
      this.add_todo_flag = !this.add_todo_flag
    },
    check ( index ) {
      this.active_index = index
     if( this.todos[index].flag){
       this.remove( index )
     }else{
       this.mask_flag = true
     }
    },
    remove ( index ) {
      this.todos.splice( index,1 )
    },
    addTodoItem ( value ) {
      console.log( 'yyb add ' )
      this.todos.push({
        id: this.todos.length + 1,
        task: value,
        flag: true
      })
    },
    getFocus () {
      this.add_todo_input = ''
    }

  },
  computed: {
    allTodos () {
      return this.todos
    },
    finishTodos () {
      //已经完成的任务
      // for some filter map forEach every
      return this.todos.filter( item => {
        return item.flag && item
      })
    },
    unFinishTodos () {
      //已经完成的任务
      // for some filter map forEach every
      return this.todos.filter( item => {
        return !item.flag && item 
      })
    },
    newTodos () {
      switch ( this.type ) {
        case 'all':
          return this.allTodos
          break;
      case 'finish':
          return this.finishTodos
          break;
        case 'unfinish':
          return this.unFinishTodos
          break;
        default:
          break;
      }
    }
  }
  }
</script>


MaskComponent.vue代码

<template>
  <!-- mask --  start -->
  <div class="mask-box" 
    @click = "maskHandler"
  >
    <div class="mask-box-bg"></div>
    <div class="card">
      <div class="card-content">
        <b class="card-content-inner"> 您确定要删除吗? </b>
        <div class="my-btn-box pull-right">

            <button 
              class="button button-warning button-fill"
              @click = "removeItem( activeIndex )"
            > 
              确定
            </button>

          </div>
      </div>
    </div>
  </div>
<!-- mask --  end -->
</template>

<script>
export default {
  props: ['activeIndex'],
  methods: {
    maskHandler () {
      this.$emit('mask')
    },
    removeItem () {
      this.$emit('remove')
    }
  }
}
</script>


<style scoped>
  .mask-box{
    width: 100%;
    height: 100%;
    position: fixed;
    left: 0; top: 0;
    z-index: 10000;
  }
  .mask-box-bg{
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0; top: 0;
    background: #000;
    opacity: .5;
  }

  .mask-box .card{
    width: 80%;
    height: 100px;
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
    border-radius: 10px;
  }
  .mask-box button{
    width: 100px;
    height: 25px;
  }
  .mask-box b{
    display: block;
  }
</style>

App.vue代码

<template>
  <div id="app">
    <lay-out></lay-out>
  </div>
</template>

<script>
import LayOut from './components/LayOut'
export default {
  name: 'app',
  components: {
    LayOut
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
*{
  list-style: none;
  padding: 0;margin: 0;
}
.my-btn-box{
  display: flex;
  padding: 10px;
}
.my-btn-box button{
  margin-left: 10px;
}
.card{
  overflow: hidden;
}

footer{
  position: fixed;
  left: 0;
  bottom: 10px;
  width: 100%;
  height: 80px;
}
footer ul{
  width: 100%;height: 100%;
  display: flex;
  justify-content: space-around;
}
footer li{
  width: 80px;
  height: 80px;
  border-radius: 50%;
}
footer li.circle{
  text-align: center;
  line-height: 80px;
}
footer li.circle.circle-success{
  border: 1px solid #006400;
  color: #006400;
}
footer li.circle.circle-success.circle-fill{
 background: #006400;
 color: white;
}

footer li.circle.circle-primary{
  border: 1px solid #00008B;
  color: #00008B;
}
footer li.circle.circle-primary.circle-fill{
 background: #00008B;
 color: white;
}

footer li.circle.circle-warning{
  border: 1px solid #FFA500;
  color: #FFA500;
}
footer li.circle.circle-warning.circle-fill{
 background: #FFA500;
 color: white;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值