最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

vue.js - How to use classes to style child component's root and non-root elements in Vue 3? - Stack Overflow

programmeradmin1浏览0评论

I'm starting to implement a reusable Vue component library for in-house use on a team of 20+ developers across a couple of applications. A common pattern I have used in the past in Vue 2 is applying a class to a child component to be able to to style it as needed from the parent. This was an intentional feature by the Vue team, according to this documentation. In Vue 2, even when inheritAttrs was false, the class (and style) attributes still fell through to the root element, perhaps for this reason. Something like this:

Parent:

<template>
  <div>
    <MyInput class="my-child" />
  </div>
</template>

<style scoped>
/* This style gets applied to the root <div> */
.my-child {
  width: 300px;
}
</style>

MyInput:

<template>
  <!-- Even with inheritAttrs: false, classes are bound here in Vue 2 -->
  <div>
    <label>...</label>
    <input v-bind="$attrs" ... />
  </div>
</template>

<script>
export default {
  inheritAttrs: false
}
</script>

In Vue 3, this was a breaking change introduced - the class now gets applied to the child that the attributes are bound to using v-bind="$attrs" (if applicable), whether using inheritAttrs: false or in the case of a multi-root component. But that means that (I believe) there is no simple way to style the root element. Nor the child element that is inheriting attributes with scoped styles, for that matter, because of how scoping works.

Parent:

<template>
  <div>
    <MyInput class="my-child" />
  </div>
</template>

<style scoped>
/* This style does nothing in Vue 3 - to the root element nor the child element */
.my-child {
  width: 300px;
}
</style>

MyInput:

<template>
  <div>
    <label>...</label>
    <!-- With inheritAttrs: false, classes are bound here in Vue 3, but can't be targeted by scoped styles -->
    <input v-bind="$attrs" ... />
  </div>
</template>

<script>
export default {
  inheritAttrs: false
}
</script>

In this situation, without creating global style rules,

  1. is there any way to apply styles to the MyInput root div from the parent? AFAIK, there isn't, except maybe something like this:

    Parent:

    <style scoped>
    div {
    ...
    }
    </style>
    

    Not very useful. Or to add something like a containerStyles prop that can be applied to the root div:

    <template>
      <div :style="containerStyles">
        <label>...</label>
        <input v-bind="$attrs" ... />
      </div>
    </template>
    
    <script>
    export default {
      inheritAttrs: false,
      props: {
        containerStyles: {
          type: Object,
          default: null
        }
      }
    }
    </script>
    
  2. what are my options for applying styles to the child input? Here are the solutions I'm aware of:

    1. Use the style attribute.
      <template>
        <MyInput style="width:300px" />
      </template>
      
    2. Use the :deep() selector.
      <template>
        <MyInput class="my-child" />
      <template>
      
      <style scoped>
      :deep(.my-child) {
        width: 300px;
      }
      </style>
      
    3. Use module styling.
      <template>
        <MyInput class="$style.myChild" />
      </template>
      
      <style module>
      .myChild {
        max-width: 300px;
      }
      </style>
      
  3. Is there a best practice for something like this? Especially if with multiple components, say for example, MyButton has the classes and styles bound to a root button element, MyInput has them bound to a child input element, and MyDialog is a multi-root component with them bound to a dialog element. How do you make these use cases consistent?

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>