my-tag 标签组件的封装
1. 创建组件 - 初始化
2. 实现功能
(1) 双击显示,并且自动聚焦
v-if v-else @dbclick 操作 isEdit
自动聚焦:
1. $nextTick => $refs 获取到dom,进行focus获取焦点
2. 封装v-focus指令
(2) 失去焦点,隐藏输入框
@blur 操作 isEdit 即可
(3) 回显标签信息
回显的标签信息是父组件传递过来的
v-model实现功能 (简化代码) v-model => :value 和 @input
组件内部通过props接收, :value设置给输入框
(4) 内容修改了,回车 => 修改标签信息
@keyup.enter, 触发事件 $emit('input', e.target.value)
---------------------------------------------------------------------
my-table 表格组件的封装
1. 数据不能写死,动态传递表格渲染的数据 props
2. 结构不能写死 - 多处结构自定义 【具名插槽】
(1) 表头支持自定义
(2) 主体支持自定义
源码:
components
MyTag.vue
<template><div class="my-tag"><inputv-if="isShow"class="input"type="text"placeholder="输入标签"v-focus@blur="isShow = false":value="value"@keyup.enter="handleEnter"/><div class="text"v-else@dblclick="handleClick">{{ value }} </div></div>
</template><script>
export default {data (){return{isShow : false}},props:{value : String },methods:{handleClick(){this.isShow = true// this.$nextTick(() =>{// this.$refs.ipt.focus()// })},handleEnter(e){if (e.target.value.trim() == '')return alert('更改为空,请重新更改')this.$emit("input",e.target.value)this.isShow = false}}
}
</script><style lang="less" scoped>.my-tag {cursor: pointer;.input {appearance: none;outline: none;border: 1px solid #ccc;width: 100px;height: 40px;box-sizing: border-box;padding: 10px;color: #666;&::placeholder {color: #666;}}}
</style>
MyTable.vue
<template><table class="my-table"><thead><slot name="head"></slot></thead><tbody><tr v-for="(item,index) in goods" :key="item.id"><slot name="body" :item="item" :index="index"></slot></tr></tbody></table>
</template><script>
export default {props:{goods : Array}
}
</script><style lang="less" scoped>
.my-table {width: 100%;border-spacing: 0;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}th {background: #f5f5f5;border-bottom: 2px solid #069;}td {border-bottom: 1px dashed #ccc;}td,th {text-align: center;padding: 10px;transition: all .5s;&.red {color: red;}}.none {height: 100px;line-height: 100px;color: #999;}
}</style>
App.vue
<template><div class="table-case"><MyTable :goods="goods"><template #head><tr><th>编号</th><th>图片</th><th>名称</th><th width="100px">标签</th></tr></template><template #body="{item,index}"><td>{{index+1}}</td><td><img :src="item.picture" /></td><td>{{ item.name }}</td><td><MyTag v-model="item.tag"></MyTag></td></template></MyTable></div>
</template><script>
import MyTag from './components/MyTag.vue';
import MyTable from './components/MyTable.vue';
export default {name: 'TableCase',data () {return {goods: [{ id: 101, picture: 'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具' },{ id: 102, picture: 'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋' },{ id: 103, picture: 'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰' },{ id: 104, picture: 'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰' },]}},components:{MyTag,MyTable}
}
</script><style lang="less" scoped>
.table-case {width: 1000px;margin: 50px auto;img {width: 100px;height: 100px;object-fit: contain;vertical-align: middle;}
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falseVue.directive("focus",{//指令所在的dom元素插入到页面中时触发inserted(el){el.focus()}
})new Vue({render: h => h(App),
}).$mount('#app')
运行结果:
双击标签后输入框自动获取焦点,并且把未更改以前的标签名显示到输入框上面。
回车以后更改完成
更改空白的话弹出提示
这些逻辑实现起来很简单,主要是表单中的表头和主体都可以进行自定义,这其中使用到了作用域插槽来传参。对组件化有着比较好的诠释。