Vue.js Demo 数据及其列表操作

codepen在线查看

演示

list.html

<!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">
    <title>Document</title>
    <script src="../bower_components/vue/dist/vue.min.js"></script>
    <link rel="stylesheet" href="font/iconfont.css">
    <link rel="stylesheet" href="css/app.css">
</head>

<body>

<!--emmet写法:section.list>h3.title{列表}+h6.tip.data-null-tip{没有数据}+(ul.list-inner>li.list-item>(div.opt-wrapper>input.opt[type="checkbox"])+(span.title{一条内容})+(div.operate>(a.btn.btn-edit[href="javascript:void(0)"]>i.icon.iconfont.icon-edit[title="编辑"])+(a.btn.btn-del[href="javascript:void(0)"]>i.icon.iconfont.icon-del[title="删除"])+(a.btn.btn-mark[href="javascript:void(0)"]>i.icon.iconfont.icon-mark[title="标记已读"])))-->
<!--div.list-statistical>(span.count{1条数据未读})+(ul.filter>li.list-item{所有数据}*3)-->
<!--section.data-entry>h3.title{添加数据}+(.form-wrapper>lable.hidden[for="dataInput"]+input.form-input.data-input[name="dataInput" placeholder="支持Enter键入"]+btn.btn.btn-add{添加})-->

    <article class="data">

        <!--添加数据-->
        <section class="data-entry">
            <h3 class="title">添加数据</h3>
            <div class="form-wrapper">
                <lable class="hidden" for="dataInput"></lable>
                <input type="text" class="form-input data-input" name="dataInput" placeholder="支持Enter键入" v-on:keyup.enter="addData" v-model="inputItem">
                <button class="btn btn-add" v-on:click="addData">添加</button>
            </div>
        </section>

        <!--筛选数据-->
        <section class="data-filter clearfix" v-show="list.length">
            <span class="count">{{noCheckedLength}} 条数据未读</span>
            <div class="filter">
                <a class="list-item" v-bind:class="{active:visibility === 'all'}" href="#all">所有数据</a>
                <a class="list-item" v-bind:class="{active:visibility === 'notmarked'}" href="#notmarked">未读数据</a>
                <a class="list-item" v-bind:class="{active:visibility === 'marked'}" href="#marked">已读数据</a>
            </div>
        </section>

        <!--数据列表-->
        <section class="data-list">
            <h3 class="title">列表</h3>
            <!--条件渲染-->
            <h6 class="tip data-null-tip" v-show="!list.length">没有数据</h6>
            <ul class="list-inner">
                <li class="list-item" v-bind:class="{active:item.isChecked, edit:item === editingItem}" v-for="item in filterList">
                    <div class="opt-wrapper">
                        <input id="CheckState" name="CheckState" type="checkbox" class="opt" v-model="item.isChecked">
                    </div>
                    <span class="title" v-on:dblclick="editData(item)"> {{item.title}} </span>
                    <div class="form-wrapper">
                        <lable class="hidden" for="DataEdit"></lable>
                        <input class="form-input" name="DataEdit" type="text" v-focus="editingItem === item" v-model="item.title" v-on:blur="updateData(item)"
                            v-on:keyup.enter="updateData(item)" v-on:keyup.esc="cancelEdit(item)">
                        <button class="btn btn-update" v-on:click="updateData(item)">更新</button>
                        <button class="btn btn-cancel" v-on:click="cancelEdit(item)">取消</button>
                    </div>

                    <div class="operate">
                        <a href="javascript:void(0)" class="btn btn-edit" v-on:click="editData(item)"><i class="icon iconfont icon-edit" title="编辑"></i></a>
                        <a href="javascript:void(0)" class="btn btn-del" v-on:click="deleteData(item)"><i class="icon iconfont icon-del" title="删除"></i></a>
                    </div>
                </li>
            </ul>
        </section>

    </article>

    <script src="js/app.js"></script>
</body>

</html>

app.js

// 存取 localStorage 中的数据
let store = {
    save(key, value) {
        localStorage.setItem(key, JSON.stringify(value));
    },
    fetch(key) {
        return JSON.parse(localStorage.getItem(key)) || [];
    }
};

let list = store.fetch('DataList');

// 数据过滤
let filterData = {
    // 所有数据
    all: function (list) {
        return list;
    },
    // 未操作数据
    notmarked: function (list) {
        return list.filter(function (item) {
            return !item.isChecked;
        })
    },
    // 已操作数据
    marked: function (list) {
        return list.filter(function (item) {
            return item.isChecked;
        })
    }
};

let vm = new Vue({
    el: ".data", // 挂载点
    data: {
        list: list, // 数据源
        inputItem: "", // 新添加数据
        editingItem: null, // 当前编辑项
        originalTitle: "", // 正在编辑的数据的原值,取消时候,以恢复
        visibility: "all" // 通过属性值变化对数据进行筛选
    },
    computed: {
        // [计算属性](https://cn.vuejs.org/v2/guide/computed.html)
        noCheckedLength() {
            return this.list.filter(function (item) {
                return !item.isChecked
            }).length
        },
        filterList:function() {
            // 过滤数据
            return filterData[this.visibility] ? filterData[this.visibility](list) : list;
        }
    },
    methods: {
        // [方法事件处理器](https://cn.vuejs.org/v2/guide/events.html)
        // 添加项至 list .
        // ES6 addData(){}
        addData: function (ev) {
            // ev,执行函数无参,默认是事件对象,有参,需要添加事件对象 "$event"
            // 事件处理函数中的this指向是当前根实例
            // if (ev.keyCode === 13) {
            this.list.push({
                // DOM触发
                // title: ev.target.value
                // 数据驱动
                title: this.inputItem,
                isChecked: false
            });
            // }
            this.inputItem = '';
        },
        deleteData(itemTemp) {
            let index = this.list.indexOf(itemTemp);
            this.list.splice(index, 1);
        },
        editData(itemTemp) {
            this.originalTitle = itemTemp.title;
            this.editingItem = itemTemp;
        },
        updateData(itemTemp) {
            this.editingItem = null;
            this.originalTitle = '';
        },
        cancelEdit(itemTemp) {
            itemTemp.title = this.originalTitle;
            this.editingItem = null;
            this.originalTitle = '';
        }
    },
    directives: {
        // 除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令。
        // 对纯 DOM 元素进行底层操作
        // 注册局部指令,在模板中任何元素上使用新的 v-focus 属性
        "focus": {
            // 钩子函数:bind inserted update componentUpdated unbind
            // 钩子函数的参数:el,binding,vnode,oldVnode
            update(el, binding) {
                if (binding.value) {
                    el.focus();
                }
            }
        }
    },
    watch: { // 浅监控 深监控
        /*
        list:function(){
            store.save("TodoList",this.list);
        }
        */
        list: {
            handler: function (list) {
                store.save("DataList", list);
            },
            deep: true
        }
    }
});

// 监听Hash
function watchHashChange() {
    let hash = window.location.hash.slice(1);
    vm.visibility = hash || 'all';
}

watchHashChange();

// https://developer.mozilla.org/zh-CN/docs/Web/Events/hashchange
window.addEventListener("hashchange", watchHashChange);

app.scss(这里上编译后的样式)

body, div, ul { margin: 0; padding: 0; }

body { font-size: 16px; }

ul { list-style: none; }

a { color: #777777; }

a:link { text-decoration: none; }

a:hover, a:focus { color: #333333; }

section { margin-top: 18px; margin-bottom: 18px; }

.clearfix:before, .clearfix:after { content: " "; display: table; }

.clearfix:after { clear: both; overflow: hidden; }

.clearfix { *zoom: 1; }

.hidden { display: none; }

.data { width: 640px; margin-right: auto; margin-left: auto; }

.form-wrapper { position: relative; height: 30px; padding-right: 55px; padding-left: 5px; border: 1px solid #333333; overflow: hidden; box-sizing: border-box; }

.form-wrapper .form-input { width: 100%; height: 28px; line-height: 28px; border: 0; }

.form-wrapper .btn { display: inline-block; position: absolute; right: 0; top: -1px; width: 50px; height: 32px; border: 0; text-align: center; vertical-align: middle; -ms-touch-action: manipulation; touch-action: manipulation; cursor: pointer; background-color: #000; color: #fff; box-sizing: border-box; }

.form-wrapper .btn:active { outline: 0; }

.tip { margin-top: 6px; margin-bottom: 6px; font-size: 1em; color: #777777; }

.data-entry .form-wrapper { width: 100%; }

.data-filter .count { float: left; }

.data-filter .filter { float: right; }

.data-filter .filter .list-item { display: inline-block; color: #777777; cursor: pointer; }

.data-filter .filter .list-item:hover, .data-filter .filter .active { color: #333333; }

.data-list .list-item { clear: both; height: 30px; padding-top: 6px; padding-bottom: 6px; line-height: 30px; border-bottom: 1px solid #eeeeee; }

.data-list .list-item .form-wrapper { display: none; width: 60%; padding-right: 110px; }

.data-list .list-item .form-wrapper .btn { top: 2px; width: 48px; height: 24px; line-height: 24px; border-radius: 12px; opacity: .5; }

.data-list .list-item .form-wrapper .btn-update { right: 52px; }

.data-list .list-item .form-wrapper .btn-cancel { right: 2px; background-color: #555555; }

.data-list .list-item .opt-wrapper, .data-list .list-item .title { float: left; }

.data-list .list-item .opt-wrapper { padding-right: 12px; }

.data-list .list-item .operate { float: right; }

.data-list .list-item .operate .btn .icon { font-size: 1.5em; }

.data-list .active { color: #777777; }

.data-list .edit .title { display: none; }

.data-list .edit .form-wrapper { float: left; display: block; }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值