插槽传值

小程序:循环的插槽中不允许访问页面数据

什么意思呢,比如有一个页面A,引入了一个组件B,B中有一个循环出来的插槽,A中使用组件B,在A中定义的数据是无法直接在插槽中使用的。

举例:
组件inner.vue

  1. <template lang="pug">
  2. view
  3. view 外面的
  4. view(v-for="(item, index) in list" :key="index")
  5. slot(v-bind:item="item")
  6. </template>
  7. <script>
  8. export default {
  9. name: 'inner',
  10. props: {
  11. list: {
  12. type: Array,
  13. default() {
  14. return []
  15. }
  16. }
  17. }
  18. }
  19. </script>

页面中引入此组件:

  1. <template lang="pug">
  2. view
  3. view {{obj.name}}
  4. inner(:list="list" v-slot='{ item }')
  5. view {{obj.name}}
  6. view {{item}}
  7. </template>
  8. <script>
  9. import inner from './inner.vue'
  10. export default {
  11. components: { inner },
  12. data() {
  13. return {
  14. obj: {
  15. name: 'hello'
  16. },
  17. list: [1,2,3,4,5]
  18. }
  19. },
  20. }
  21. </script>

在H5中渲染正常:
Snipaste_2021-06-01_15-53-15.png

在小程序中:
Snipaste_2021-06-01_15-53-59.png

可以看出,在小程序中,放到循环插槽中,是不能获取到父页面中的值的。

对此,只能采取一个折中的解决方案:将需要的值传入子组件之中,再暴露给父页面。
具体修改如下:
组件inner.vue

  1. <template lang="pug">
  2. view
  3. view 外面的
  4. view(v-for="(item, index) in list" :key="index")
  5. slot(v-bind:item="item" v-bind:data="extraData")
  6. </template>
  7. <script>
  8. export default {
  9. name: 'inner',
  10. props: {
  11. list: {
  12. type: Array,
  13. default() {
  14. return []
  15. }
  16. },
  17. extraData: {
  18. type: Object,
  19. default() {
  20. return {}
  21. }
  22. }
  23. }
  24. }
  25. </script>

用一个props(extraData)接收父页面传入的数据,再使用v-bind将其暴露。

页面中:

  1. <template lang="pug">
  2. view
  3. view {{obj.name}}
  4. inner(:list="list" :extraData="obj" v-slot='{ item, data }')
  5. view {{data.name}}
  6. view {{item}}
  7. </template>
  8. <script>
  9. import inner from './inner.vue'
  10. export default {
  11. components: { inner },
  12. data() {
  13. return {
  14. obj: {
  15. name: 'hello'
  16. },
  17. list: [1,2,3,4,5]
  18. }
  19. },
  20. }
  21. </script>

通过 v-slot将其解构,获取数据。

在小程序中:
Snipaste_2021-06-01_16-03-52.png

写法有点挫,但没办法,只能这样搞定。

一个包含计算属性的示例:

  1. <template lang="pug">
  2. Layout(:type='2', title='测试', :showFooter='false')
  3. view {{computedName}}
  4. inner(:list="list" :extraData="computedName" v-slot='{ item, data }')
  5. view {{data}}
  6. view {{item}}
  7. </template>
  8. <script>
  9. import inner from './inner.vue'
  10. export default {
  11. components: { inner },
  12. data() {
  13. return {
  14. obj: {
  15. name: 'hello'
  16. },
  17. list: [1,2,3,4,5]
  18. }
  19. },
  20. computed: {
  21. computedName() {
  22. return this.obj.name + ' world'
  23. }
  24. }
  25. }
  26. </script>

如果计算属性是vuex的值,最好是直接放到组件中。
举例:
组件inner.vue

  1. <template lang="pug">
  2. view
  3. view 外面的
  4. view(v-for="(item, index) in list" :key="index")
  5. slot(v-bind:item="item" v-bind:data="skin")
  6. </template>
  7. <script>
  8. import { mapGetters } from 'vuex'
  9. export default {
  10. name: 'inner',
  11. props: {
  12. list: {
  13. type: Array,
  14. default() {
  15. return []
  16. }
  17. },
  18. },
  19. computed: {
  20. ...mapGetters({
  21. skin: 'skin'
  22. })
  23. },
  24. }
  25. </script>

页面中引入:

  1. <template lang="pug">
  2. view
  3. view {{obj.name}}
  4. inner(:list="list" v-slot='{ item, data }')
  5. view(:class="data.tc1") {{item}}
  6. </template>
  7. <script>
  8. import inner from './inner.vue'
  9. export default {
  10. components: { inner },
  11. data() {
  12. return {
  13. obj: {
  14. name: 'hello'
  15. },
  16. list: [1,2,3,4,5]
  17. }
  18. },
  19. }
  20. </script>

之前试过将vuex的计算属性传入,但是会得到不可预期的效果,不知道原因。

小程序:循环的插槽中不允许使用过滤器

这点比较头疼,小程序不支持在循环插槽中Vue中的过滤器语法。

比如有如下过滤器:

  1. Vue.filter('date', (value, len = 10) => {
  2. if (!value) return ''
  3. value = value.slice(0, len)
  4. return value
  5. })

组件还是同上面 小程序:循环的插槽中不允许数据穿透 的一样。

在页面中调用:

  1. <template lang="pug">
  2. view
  3. view {{'2021-01-01 12:00:00' | date}}
  4. inner(:list="list" v-slot='{ item }')
  5. view {{'2021-01-01 12:00:00' | date}}
  6. </template>

小程序端编译出来仍然是无效的。

浏览器:
Snipaste_2021-06-01_16-51-25.png

小程序:
Snipaste_2021-06-01_16-51-55.png

小程序:循环的插槽中不允许使用页面方法

其实看懂了上面两点,这一点也是一样的。说白了,其实就是:

  1. 在小程序中,循环插槽不允许使用页面中的方法、过滤器、数据。

示例:

  1. <template lang="pug">
  2. view
  3. view {{parseTime('2021-01-01 12:00:00')}}
  4. inner(:list="list" v-slot='{ item }')
  5. view {{parseTime('2021-01-01 12:00:00')}}
  6. </template>
  7. <script>
  8. import inner from './inner.vue'
  9. export default {
  10. components: { inner },
  11. data() {
  12. return {
  13. list: [1,2,3,4,5]
  14. }
  15. },
  16. methods: {
  17. parseTime(time) {
  18. return time.slice(0, 10)
  19. }
  20. }
  21. }
  22. </script>

或者使用计算属性:

  1. <template lang="pug">
  2. view
  3. view {{parseTime('2021-01-01 12:00:00')}}
  4. inner(:list="list" v-slot='{ item }')
  5. view {{parseTime('2021-01-01 12:00:00')}}
  6. </template>
  7. <script>
  8. import inner from './inner.vue'
  9. export default {
  10. components: { inner },
  11. data() {
  12. return {
  13. list: [1,2,3,4,5]
  14. }
  15. },
  16. computed: {
  17. parseTime() {
  18. return time => time.slice(0, 10)
  19. }
  20. },
  21. }
  22. </script>

可以看到,在H5端正常,小程序端仍然是不能渲染。

解决方案:暂未找到什么好的解决方案。

针对这个问题,我向uniapp提了一个issue:小程序:循环的插槽中不允许访问页面数据