Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何做到自适应?我想在移动端优美的展示 #45

Closed
9yues opened this issue Sep 15, 2017 · 37 comments
Closed

如何做到自适应?我想在移动端优美的展示 #45

9yues opened this issue Sep 15, 2017 · 37 comments

Comments

@9yues
Copy link

9yues commented Sep 15, 2017

No description provided.

@xiguaxigua
Copy link
Contributor

“优美的展示” 可以具体一点吗?
比如:想要宽度自适应?高度自适应?或是几个图并排展示数量不定?

@9yues
Copy link
Author

9yues commented Sep 15, 2017

我已经解决了谢谢

@LeeWgg
Copy link

LeeWgg commented Oct 24, 2017

怎么解决啊?我这边总是报 Can't get dom width or height

@xiguaxigua
Copy link
Contributor

用在什么场景下?

@xiguaxigua
Copy link
Contributor

如果是容器初始宽度未知的话,可以参考一下这个例子 https://elemefe.github.io/v-charts/#/skill-demo?id=%e5%ae%b9%e5%99%a8%e7%9a%84%e5%88%9d%e5%a7%8b%e5%ae%bd%e5%ba%a6%e6%9c%aa%e7%9f%a5

@LeeWgg
Copy link

LeeWgg commented Oct 24, 2017

.canvasChart
      width: 100%
      height: 400px
      margin-bottom: pxTem(200)
<div class="canvasChart">
              <ve-line ref='chart1' :after-config="afterConfig" :data-zoom="dataZoom" :legend-visible="false" :colors="chartColors" :width="chartWidth" :data="chartData"></ve-line>
            </div>
```
我设置了容器宽度为什么还是报Can't get dom width or height

@LeeWgg
Copy link

LeeWgg commented Oct 24, 2017

如果我定死高宽,图表是可以显示出来,但是依然会报Can't get dom width or height

@xiguaxigua
Copy link
Contributor

当width为100%时,如果容器因素的不存在或不被显示,相当于width没有设置,此时Echarts是获取不到容器宽度的。解决的方法类似上面提供的那个例子,在确定容器已经渲染好了(一般是在nextTick之后),调用一下resize方法,这样图就可以显示出来了。

@LeeWgg
Copy link

LeeWgg commented Oct 25, 2017

那nextTick写在vue的哪个钩子里?

@xiguaxigua
Copy link
Contributor

xiguaxigua commented Oct 25, 2017

一般是mounted,如果容器的渲染是在mounted后执行的,比如是通过某个变量控制,那就要在这个变量变化后(一般写在watch里)执行nextTick。

@LeeWgg
Copy link

LeeWgg commented Oct 25, 2017

容器宽高我是定好了的,使用mounted方法还是不行

mounted () {
      this.$nextTick(() => {
        this.$refs[`chart1`].echarts.resize()
      })
    }

@xiguaxigua
Copy link
Contributor

方便抽象出一个例子看看吗?或者描述一下大致的 dom 结构,使用场景。

@LeeWgg
Copy link

LeeWgg commented Oct 25, 2017

dom结构就是最上面列举出来的那个

@xiguaxigua
Copy link
Contributor

升个版本试试 v1.11.3

@xiguaxigua
Copy link
Contributor

如果可以的话,在 jsfiddle 上简化出一个可以重现这个问题的例子吧,这样可以更有针对性的解决你遇到的问题。

@LeeWgg
Copy link

LeeWgg commented Oct 25, 2017

谢谢,问题已经解决

@GuangxinZhang
Copy link

麻烦问下怎么解决的?

@xiguaxigua
Copy link
Contributor

@GuangxinZhang 是出现什么报错了吗?还是展示的时候样式有问题?

@GuangxinZhang
Copy link

GuangxinZhang commented Dec 2, 2017

@xiguaxigua 我的页面刷新后,曲线图会溢出,在mounted里resize也不起作用,改变窗口大小后,就没问题了。每次刷新页面就又会溢出,感觉像echarts先于父元素渲染了大小,echarts比父元素大。

@xiguaxigua
Copy link
Contributor

方便抽出一个示例吗?

@GuangxinZhang
Copy link

GuangxinZhang commented Dec 2, 2017

@xiguaxigua 我点击按钮事件,执行resize,是没问题的,但是每次刷新页面,echarts就回溢出。

<template>
    <v-container fluid>
      <v-container grid-list-md text-xs-center>
        <v-layout row wrap>
          <v-flex lg9>
            <v-card ref="abc">
              <ve-line :data="chartData" :settings="chartSettings" ref="chart1"></ve-line>
            </v-card>
          </v-flex>
          <v-flex lg3>
            <v-card>
              <ve-line :data="chartData" :settings="chartSettings" ref="chart2"></ve-line>
            </v-card>
          </v-flex>
        </v-layout>
      </v-container>
      <v-container grid-list-md text-xs-center>
        <div>
          <v-btn color="primary" v-on:click="button">Primary</v-btn>
        </div>
      </v-container>
    </v-container>
</template>


<script>
export default {
  data: function () {
    return {
      chartData: {
        columns: ['日期', '成本', '利润', '占比', '其他'],
        rows: [
          { '日期': '1月1日', '成本': 1523, '利润': 1523, '占比': 0.12, '其他': 100 },
          { '日期': '1月2日', '成本': 1223, '利润': 1523, '占比': 0.345, '其他': 100 },
          { '日期': '1月3日', '成本': 2123, '利润': 1523, '占比': 0.7, '其他': 100 },
          { '日期': '1月4日', '成本': 4123, '利润': 1523, '占比': 0.31, '其他': 100 },
          { '日期': '1月5日', '成本': 3123, '利润': 1523, '占比': 0.12, '其他': 100 },
          { '日期': '1月6日', '成本': 7123, '利润': 1523, '占比': 0.65, '其他': 100 }
        ]
      },
      chartSettings: {
        stack: { '售价': ['成本', '利润'] },
        area: true
      },
      width: '90%',
      height: '350px'
    }
  },
  mounted: function () {
    that.$refs[`chart1`].echarts.resize()
  },
  methods: {
    button () {
      this.$refs[`chart1`].echarts.resize()
      this.$refs[`chart2`].echarts.resize()
    }
  }
}
</script>

package.json
"dependencies": {
"v-charts": "^1.12.0",
"vue": "^2.5.2",
"vue-resource": "^1.3.4",
"vue-router": "^3.0.1",
"vuetify": "^0.17.3"
},

@xiguaxigua
Copy link
Contributor

在 mounted 内部增加 nextTick 修改一下看看:

mounted: function () {
  this.$nextTick(function () {
    that.$refs[`chart1`].echarts.resize()
  })
},

@GuangxinZhang
Copy link

GuangxinZhang commented Dec 2, 2017

image
没有变化,奇怪的是当我改变浏览器窗口大小的时候,echarts会自动resize,变成正常的大小。

@GuangxinZhang
Copy link

image
这个是正常大小显示

@GuangxinZhang
Copy link

大概是这个问题,我有个左侧菜单,echarts渲染的时候,没有考虑左侧菜单的大小,上面那个代码单独显示echarts图形是没有问题的,我加上左侧菜单以后,就显示不正常了。

@GuangxinZhang
Copy link

image
image

@xiguaxigua
Copy link
Contributor

侧边栏是可以切换显示隐藏的吗?

@GuangxinZhang
Copy link

GuangxinZhang commented Dec 2, 2017

@xiguaxigua 嗯嗯,是的
侧边栏隐藏后,显示就正常了。

@xiguaxigua
Copy link
Contributor

对于溢出的问题,一般是由于 echarts 渲染时的 html 结构的宽度还不是预期的宽度导致的,解决的方案是在合适的时机触发一下 echarts 的 resize 方法。

不是很了解你得页面里是如何实现这个侧边栏的,我这边写了一个小例子 https://jsfiddle.net/vue_echarts/qc441x6m/1/ ,跟你写的这个样式差不多的,可以看一下里面的内容那些不一样,也可以把你写的 HTML 结构抽出一个大致的例子,这样解决起来可能更加方便一些。

@GuangxinZhang
Copy link

GuangxinZhang commented Dec 2, 2017

是这样的,整个页面是一个布局组件,头部和左侧是固定的,内容区是变化的内容


export default new Router({
  routes: [
    { path: '/',
      name: 'Root',
      component: Layout,
      meta: { requiresAuth: true },
      children: [
        {
          path: 'index',
          component: Index
        }
      ]
    },
    { path: '/test', name: 'Test', component: Test, meta: { requiresAuth: true } },
    { path: '/login', name: 'Login', component: Login, meta: { requiresAuth: false } }
  ]
})

layout.vue:

<template>
  <v-app>
    <v-navigation-drawer
      fixed
      clipped
      app
      v-model="drawer"
    >
      <v-list dense>
        <template v-for="(item, i) in items">
          <v-layout
            row
            v-if="item.heading"
            align-center
            :key="i"
          >
            <v-flex xs6>
              <v-subheader v-if="item.heading">
                {{ item.heading }}
              </v-subheader>
            </v-flex>
            <v-flex xs6 class="text-xs-center">
              <a href="#!" class="body-2 black--text">EDIT</a>
            </v-flex>
          </v-layout>
          <v-list-group v-else-if="item.children" v-model="item.model" no-action>
            <v-list-tile slot="item" @click="">
              <v-list-tile-action>
                <v-icon>{{ item.model ? item.icon : item['icon-alt'] }}</v-icon>
              </v-list-tile-action>
              <v-list-tile-content>
                <v-list-tile-title>
                  {{ item.text }}
                </v-list-tile-title>
              </v-list-tile-content>
            </v-list-tile>
            <v-list-tile
              v-for="(child, i) in item.children"
              :key="i"
              @click=""
            >
              <v-list-tile-action v-if="child.icon">
                <v-icon>{{ child.icon }}</v-icon>
              </v-list-tile-action>
              <v-list-tile-content>
                <v-list-tile-title>
                  {{ child.text }}
                </v-list-tile-title>
              </v-list-tile-content>
            </v-list-tile>
          </v-list-group>
          <v-list-tile v-else @click="">
            <v-list-tile-action>
              <v-icon>{{ item.icon }}</v-icon>
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>
                <router-link :to="{path: item.route}">{{ item.text }}</router-link>
              </v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </template>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar
      color="blue-grey darken-3"
      dark
      app
      clipped-left
      fixed
    >
      <v-toolbar-title :style="$vuetify.breakpoint.smAndUp ? 'width: 300px; min-width: 250px' : 'min-width: 72px'" class="ml-0 pl-3">
        <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
        <span class="hidden-xs-only">APP</span>
      </v-toolbar-title>
      <div class="d-flex align-center" style="margin-left: auto">
        <v-menu bottom left>
          <v-btn icon slot="activator" dark>
            <v-icon large>account_circle</v-icon>
          </v-btn>
          <v-list>
            <v-list-tile @click="profile">
              <v-list-tile-title>个人信息</v-list-tile-title>
            </v-list-tile>
            <v-list-tile @click="logout">
              <v-list-tile-title>退出登录</v-list-tile-title>
            </v-list-tile>
          </v-list>
        </v-menu>
      </div>
    </v-toolbar>
    <v-content>
      <router-view :drawer="drawer">
        <v-container fluid></v-container>
      </router-view>
    </v-content>
    <v-footer app></v-footer>
    <v-dialog v-model="dialog" max-width="500px">
      <v-card>
        <v-card-title>
          <span>退出成功!{{ seconds }}秒后跳转至登录页...</span>
          <v-spacer></v-spacer>
        </v-card-title>
      </v-card>
    </v-dialog>
  </v-app>
</template>

<style>
a {
    text-decoraction: none;
}
.router-link-active {
    text-decoration: none;
}
</style>

<script>
  export default {
    data: () => ({
      seconds: 3,
      interval_flag: '',
      dialog: false,
      drawer: null,
      items: [
        { icon: 'home', text: '概览', route: '/index' },
        { icon: 'history', text: 'Frequently contacted', route: '/login' },
        { icon: 'content_copy', text: 'Duplicates' }
      ]
    }),
    props: {
      source: String
    },
    methods: {
      // 登录逻辑
      profile () {
        console.log('profile')
      },

      logout () {
        localStorage.setItem('STORAGE_TOKEN', '')
        this.dialog = true
        this.interval_flag = setInterval(() => {
          this.seconds = this.seconds - 1
          if (this.seconds <= 0) {
            clearInterval(this.interval_flag)
            this.$router.push('/login')
          }
        }, 1000)
      }
    }
  }
</script>

index.vue:

<template>
  <v-container fluid>
    <v-container grid-list-md text-xs-center>
      <v-layout row wrap>
        <v-flex lg9>
          <v-card ref="abc">
            <ve-line :data="chartData" :settings="chartSettings" ref="chart1"></ve-line>
          </v-card>
        </v-flex>
        <v-flex lg3>
          <v-card>
            <ve-line :data="chartData" :settings="chartSettings" ref="chart2"></ve-line>
          </v-card>
        </v-flex>
      </v-layout>
    </v-container>
    <v-container grid-list-md text-xs-center>
      <div>
        <v-btn color="primary" v-on:click="button">Primary</v-btn>
      </div>
    </v-container>
  </v-container>
</template>

<script>
export default {
  props: {
    drawer: {
      type: Boolean
    }
  },
  data: function () {
    return {
      chartData: {
        columns: ['日期', '成本', '利润', '占比', '其他'],
        rows: [
          { '日期': '1月1日', '成本': 1523, '利润': 1523, '占比': 0.12, '其他': 100 },
          { '日期': '1月2日', '成本': 1223, '利润': 1523, '占比': 0.345, '其他': 100 },
          { '日期': '1月3日', '成本': 2123, '利润': 1523, '占比': 0.7, '其他': 100 },
          { '日期': '1月4日', '成本': 4123, '利润': 1523, '占比': 0.31, '其他': 100 },
          { '日期': '1月5日', '成本': 3123, '利润': 1523, '占比': 0.12, '其他': 100 },
          { '日期': '1月6日', '成本': 7123, '利润': 1523, '占比': 0.65, '其他': 100 }
        ]
      },
      chartSettings: {
        stack: { '售价': ['成本', '利润'] },
        area: true
      },
      width: '90%',
      height: '350px'
    }
  },
  mounted: function () {
    console.log('------------------------------')
    console.log(this.drawer)
    this.$refs[`chart1`].echarts.resize()
  },
  methods: {
    button () {
      this.$refs[`chart1`].echarts.resize()
      this.$refs[`chart2`].echarts.resize()
    }
  },
  watch: {
    drawer (newValue, oldValue) {
      this.$refs[`chart1`].echarts.resize()
      this.$refs[`chart2`].echarts.resize()
      console.log(newValue)
    }
  }
}
</script>

通过点击按钮显示隐藏侧边栏,我传递了{{drawer}}点击变量到index.vue,监听变化,并且重置echarts大小,能正常收到变量值,但是重置不起作用,感觉像echarts在以最大的窗口为基准resize,而不是当前的index.vue组件。

@GuangxinZhang
Copy link

应该是这样的:Vue 异步执行 DOM 更新,内容区可能比侧边栏优先渲染,这是echarts获取到的父元素的大小是整个窗口的大小,echarts已经设置了大小,然后侧边栏才渲染,官方解决方案确实是用Vue.nextTick(callback),但是我在index.vue的mounted方法里执行了这个,的确不起作用,官方提到如果执行环境不支持nextTick,可以使用setTimeout,于是我设置了以下方法,这时问题解决了:

  mounted: function () {
    setTimeout(() => {
      console.log('------------------------------')
      this.$refs[`chart1`].echarts.resize()
      this.$refs[`chart2`].echarts.resize()
    }, 200)
    // this.$nextTick(function () {
    //   this.$refs[`chart1`].echarts.resize()
    //   this.$refs[`chart2`].echarts.resize()
    // })
  },

但是这个方法实在是太不优雅,而且图形会卡顿一下,我设置100ms都有时候会无法显示正常

@xiguaxigua
Copy link
Contributor

xiguaxigua commented Dec 4, 2017

@GuangxinZhang
试试把引入 css 的方式改成
import 'vuetify/dist/vuetify.min.css'

@GuangxinZhang
Copy link

@xiguaxigua 没有效果~

@xiguaxigua
Copy link
Contributor

xiguaxigua commented Dec 4, 2017

方便让我看一下你的整个项目吗?

我这边没办法重现,不好去判断到底是哪里的问题。

@xiguaxigua
Copy link
Contributor

或者是在 jisfiddle 或者 codesandbox 上写一个例子

@GuangxinZhang
Copy link

@xiguaxigua
Copy link
Contributor

image

https://73jj91oq6j.codesandbox.io/#/index

修改了一个css,看下在你的项目里能不能修复样式的问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants