vue开发每日一学:多个tab标签的滑动展示效果。当创建的tab标签超出页面可视区域时自动滚动一个tab标签距离,并可手动点击滚动tab标签。
- <template>
- <div>
- <button @click="add">添加</button>
- <div>
- <i @click="previous"><<</i>
- <i @click="next">>></i>
- <div ref="tabs">
- <div>
- <div v-for="(item,index) in tabs" :key="index"
- :class="{'tab-item-action':actionName === item.name ,'tab-item':actionName !== item.name}"
- @click.stop="clickTab(item.name,index)">
- <span>{{item.meta.title}}</span>
- <i @click.stop="close(item.name)"></i>
- </div>
- </div>
- </div>
- </div>
- <div>
- <div>{{actionName}}</div>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: "index",
- data() {
- return {
- tabs: [],
- moveX: 0,
- count: 1,
- unoccupied: 0,
- tabsCount: 0,
- actionName: 'test1'
- }
- },
- watch: {
- actionName(val) {
- let len = this.tabs.length
- // 如有重复数据退出后续函数执行
- for (let i = 0; i < len; i++) {
- if (this.tabs[i].name === val) {
- this.$nextTick(() => {
- this.translateX((i + 1 - this.tabsCount) * this.width - this.unoccupied)
- })
- return
- }
- }
- this.tabs.push({
- name: `test${this.count}`,
- meta: {
- title: `test${this.count}`
- }
- })
- this.$nextTick(() => {
- // (总共有多少个tabs - 未偏移时可见的元素个数) * 单个tab标签元素长度 - 被遮挡tab元素的可见部分的宽度
- this.translateX((this.tabs.length - this.tabsCount) * this.width - this.unoccupied)
- })
- }
- },
- mounted() {
- this.tabs.push({
- name: `test${this.count}`,
- meta: {
- title: `test${this.count}`
- }
- })
- this.$nextTick(() => {
- let tabs = this.$refs.tabs
- let getStyle = getComputedStyle(tabs.children[0].children[0], null)
- let marginLeft = parseFloat(getStyle.marginLeft.substr(0, getStyle.marginLeft.length - 2))
- let marginRight = parseFloat(getStyle.marginRight.substr(0, getStyle.marginRight.length - 2))
- // 元素实际宽度 = 元素的宽度 + 外边距
- this.width = marginLeft + marginRight + tabs.children[0].children[0].offsetWidth
- /**
- * 以下注释计算方式用于理解实现逻辑
- **/
- // // 可视区域能放入多少个元素 = 可视区域的宽度 / 子元素实际宽度
- // let num = tabs.offsetWidth / this.width
- // // 被遮挡tab元素的可见部分的宽度 = 可见区域的宽度 - (子元素实际宽度 * num转为整数)
- // this.unoccupied = tabs.offsetWidth - (this.width * parseInt(num))
- // 最终精简为取余(得数跟上面的计算是一样的)
- this.unoccupied = tabs.offsetWidth % this.width
- // 转为整数
- this.tabsCount = parseInt(tabs.offsetWidth / this.width)
- })
- },
- methods: {
- add() {
- this.count++
- this.actionName = `test${this.count}`
- },
- /**
- * 切换tab标签页
- **/
- clickTab(name) {
- if (this.actionName !== name) {
- this.actionName = name
- }
- },
- /**
- * 关闭tab标签页
- **/
- close(name) {
- let len = this.tabs.length
- let jumpName = null
- if (len > 1) {
- for (let i = 0; i < len; i++) {
- if (this.tabs[i].name === name) {
- this.tabs.splice(i, 1)
- jumpName = this.tabs[i ? i - 1 : 0].name
- if (this.actionName !== jumpName && name === this.actionName) {
- this.actionName = jumpName
- }
- this.$nextTick(() => {
- this.previous()
- })
- return
- }
- }
- }
- },
- /**
- * 往右偏移
- **/
- next() {
- // scrollWidth获取不准确
- // 使用this.width * this.tabs.length计算出总长度
- let totalWidth = this.width * this.tabs.length
- this.$nextTick(() => {
- let dom = this.$refs.tabs
- // 可视区域 < 滚动区域(滚动区域大于可视区域才可以移动)
- // 移动距离 + 可视区域 = 滚动区域的宽度(上一次的宽度,当点击时才是实际宽度)< 滚动区域
- if (dom.clientWidth < totalWidth && this.moveX + dom.clientWidth < totalWidth) {
- // this.moveX为0减去空余空间的宽度
- this.moveX += this.moveX ? this.width : this.width - this.unoccupied
- this.translateX(this.moveX)
- }
- })
- },
- /**
- * 往左偏移
- **/
- previous() {
- if (this.moveX > 0) {
- this.moveX -= this.width
- this.translateX(this.moveX)
- }
- },
- /**
- * 开始移动dom
- **/
- translateX(x) {
- this.moveX = x < 0 ? 0 : x
- this.$refs.tabs.children[0].style.transform = `translateX(-${this.moveX}px)`
- }
- }
- }
- </script>
- <style scoped>
- .main-box {
- height: 500px;
- width: 500px;
- padding: 10px 20px 20px 20px;
- .main-box-tab {
- position: relative;
- padding: 10px 20px;
- overflow: hidden;
- & > i {
- position: absolute;
- cursor: pointer;
- bottom: 15px;
- &:nth-child(1) {
- left: 0;
- }
- &:nth-child(2) {
- right: 0;
- }
- }
- .main-box-tab-content {
- overflow: hidden;
- .main-box-tab-roll {
- transition: transform .5s;
- display: flex;
- align-items: center;
- div {
- flex-shrink: 0;
- cursor: pointer;
- width: 130px;
- height: 25px;
- margin: 0 5px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- span, i {
- font-size: 12px;
- }
- span {
- margin-left: 10px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
- i {
- margin-right: 10px;
- }
- }
- }
- }
- .tab-item {
- color: #cccccc;
- background-color: rgba(255, 255, 255, .5);
- border-radius: 0 1px 0 1px;
- border: 1px solid #052141;
- }
- .tab-item-action {
- color: #ffffff;
- background: rgba(0, 180, 255, 0.8);
- border-radius: 0 1px 0 1px;
- border: 1px solid #1E2088;
- }
- }
- .main-box-content {
- height: calc(100% - 70px);
- padding: 10px;
- border: 1px saddlebrown solid;
- background-size: 100% 100%;
- }
- }
- </style>
大家可以放到vue开发软件里试试哦。
网友评论文明上网理性发言 已有0人参与
发表评论: