vue小目标 记录

作者参照他人效果图实现组件,过程中对代码进行修改,如用自定义指令实现 input 自动获得焦点。复习了 v-show、v-model 等知识点,还提及组件结构标签选择、单选框处理及 CSS 样式花费时间较多,最后提醒下次计时避免浪费时间。
  • 前言
    参照别人的效果图自己实现的过程,本想附上链接,但是来源很多,so pass。

  • 效果

在这里插入图片描述

  • 代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src='https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js'></script>
    <title>小目标列表</title>
    <style type='text/css'>
        html{
            font-size: 16px/1.6;
        }
        #goal-items{
            min-width: 900px;
            width: 80%;
            margin: auto;
            border: 2px solid #939393;
            padding: 5px 20px 5px 20px;
            font:1rem "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif;
            box-sizing: border-box;
        }
        .input-goal{
            line-height: 2;
            font-size: 0.9rem;
            width: 100%;
            padding-left: 10px;
        }
        #goal-items{
            font-size: 0.9rem;
        }
        #goal-items ul{
            list-style: none;
            padding: 0;
        }
        .item-out-div{
            margin: 0;
            padding: 0 8px 0 8px;
            vertical-align: middle;
        }
        .item-out-div:hover{
            border: 1px solid rgb(6, 104, 233);
        }
        .item-checkbox{
            display: inline-block;
            width: 8px;
            height: 8px;
            border: 2px solid #939393;
            margin: auto;
            margin-right: 10px;
        }
        .item-checkbox-checked{
            border: 2px solid #1212ff;
            background: #1212ff;
        }
        .item-input{
            width: 90%;
            line-height: 35px;
            border: 0;
            height: 35px;
            box-sizing: border-box;
            letter-spacing: 1;
        }
        .item-span{
            display: inline-block;
            width: 90%;
            line-height: 35px;
            border: 0;
            height: 35px;
            letter-spacing: 1;
        }
        .item-btn{
            width: 40px;
            border: 0;
            background: transparent;
            color: rgb(98, 48, 235);
            outline: none;
            visibility: hidden;
        }
        .item-out-div:hover .item-btn{
            visibility: visible;
        }
    </style>
    <script>
        window.onload = function(){
            Vue.component('goal-item', {
                data(){
                    return {
                        checked: false
                    }
                },
                props: {
                    item: {
                        type: Object,
                        required: true,
                    }
                },
                template: `
                    <div>
                        <span
                            :class="{'item-checkbox': true, 'item-checkbox-checked': item.finished}"
                            @click='item.finished = !item.finished'
                        ></span>
                        <input
                            type='text'
                            class="item-input"
                            ref='input'
                            :value='item.content'
                            @keyup.enter='changeInput($event.target.value, true)'
                            @keyup.esc='changeInput($event.target.value, false)'
                            @blur='changeInput($event.target.value, true)'
                            v-show='checked'
                            v-focus
                        />
                        <span class="item-span" v-show='!checked' @click='changeCheck'>{{ item.content }}</span>
                        <button 
                            class='item-btn'
                            @click='$emit("delete", item.id)'
                        >X</button>
                    </div>
                `,
                methods: {
                    changeInput(data, flag){
                        flag && data && (this.item.content = data);
                        this.checked = false;
                    },
                    changeCheck(){
                        this.checked = true;
                        // setTimeout(()=>{this.$refs.input.focus()}, 50)
                    }
                },
                directives: {
                    focus(el){  
                        el.focus();
                    } 
                    //focus: {bind:function(){}, update:function(){}}
                    //=focus:function(){}
                    //=focus(){}
                }
            })
            var vm = new Vue({
                el: '#goal-items',
                data: {
                    indexGoal: 0,
                    radioCheck: 'all',
                    inputValue: '',
                    GoalItems: [
                        {
                            id: 0,
                            content: 'HTML5',
                            finished: false
                        },
                        {
                            id: 1,
                            content: 'CSS3',
                            finished: false
                        },
                        {
                            id: 2,
                            content: 'JavaScript',
                            finished: false
                        },
                        {
                            id: 3,
                            content: 'VUE',
                            finished: false
                        }
                    ]
                },
                computed: {
                    allGoals(){
                        return this.GoalItems.length;
                    },
                    finishedGoals(){
                        return this.GoalItems.filter((goal)=>{
                            return goal.finished
                        }).length;
                    },
                    showGoals(){
                        if(this.radioCheck === 'all'){
                            return this.GoalItems;
                        }else if(this.radioCheck === 'finish'){
                            return this.GoalItems.filter(goal=>{
                                return goal.finished;
                            })
                        }else if(this.radioCheck === 'undone'){
                            return this.GoalItems.filter(goal=>{
                                return !goal.finished;
                            })
                        }else{
                            return []
                        }
                    }
                },
                methods: {
                    deleteItem(id){
                        this.GoalItems = this.GoalItems.filter((goal)=>{
                            return goal.id!==id;
                        })
                    },
                    addGoal(data){
                        data.trim() && this.GoalItems.push({
                            id: this.indexGoal++,
                            content: data,
                            finished: false
                        })
                    }
                },
                created(){
                    this.indexGoal = this.GoalItems.length;
                }
            })
        }
    </script>
</head>
<body>
    <div id='goal-items'>
        <h2>小目标列表</h2>
        <h4>添加小目标</h4>
        <input 
            class='input-goal' 
            type='text' 
            :value='inputValue' 
            placeholder="输入小目标后,按回车确认" 
            @keyup.enter='addGoal($event.target.value)'
        >
        <p>共有{{ allGoals }}个目标,已完成{{ finishedGoals }},还有{{ allGoals-finishedGoals }}条未完成</p>
        <label><input type='radio' v-model:checked='radioCheck' value='all'>所有目标</label>
        <label><input type='radio' v-model:checked='radioCheck' value='finish'>已完成目标</label>
        <label><input type='radio' v-model:checked='radioCheck' value='undone'>未完成目标</label>
        <ul>
            <li
                class='item-out-div'
                is='goal-item'
                v-for='item in showGoals'
                :key='item.id'
                :item='item'
                @delete='deleteItem($event)'
            ></li>
        </ul>
        <p ></p>
    </div>
</body>
</html>

  • 复习的知识点

在这里插入图片描述在这里插入图片描述在这里插入图片描述

这里有部分修改: 就是input显示自动获得焦点
原先我是用setTimeout来实现的,当时也觉得不妥,没有更好的方法,后来看了人家的实现,是可以使用自定义指令的,自定义指令可以直接操作element
修改的截图:
在这里插入图片描述
代码修改了,原有的截图没有改。

  • 总结
    这里复习了几个知识点:
    v-show 【我一开始真的没想到两个节点可以这样显示 我还在抠css class的display
    v-model 【除了text textarea的input事件是value=Xevent.target.value 其他的都不简单。。
    v-bind:class 【对象数组的绑定
    vm.$refs.xx 【这里为了实现input聚焦或失焦focus()
    计算属性有时候很重要!!
    还有就是结构理解: 试过p span input各种 最后决定用的现在的标签 对 经验太少!

总体来说不难,为什么用了那么多的时间呢
1.组件结构的标签选择及样式浪费了很多时间(尤其是点击选项的时候显示为input --2h) --开写到结束: 4h
2.单选框用的时间稍久,因为自己在试图实现响应change的函数 为什么要实现这个呢 因为单选框改变要改变下面显示的项目 发现不能实现后 直接把项目遍历数组改成了计算属性 响应式改变 --2h
3. css抠的时间久了点

–下次再写什么东西都计好时,太浪费时间了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值