Component是一个强大的Vue功能,允许扩展基本HTML元素以封装可重用代码。
我的文件夹结构如下所示: /成分 /节 /图像网格 ImageGrid.vue /联系部分 ContactSection.vue 在 Vue 文件中,我使用以下命令注册组件...
我的 v 卡上有标题、子标题、图标和按钮。我的目标是将创建按钮放在右侧,但我似乎无法做到这一点。 ... 我的 v 卡上有标题、子标题、图标和按钮。我的目标是将创建按钮放在右侧,但我似乎无法做到这一点。 <template> <v-row class="pl-5"> <v-card class="pl-5" elevation="0"> <v-card-title> <v-icon left x-large color="primary">{{ icon }}</v-icon> <span class="font-weight-bold">{{ title }}</span> </v-card-title> <v-card-subtitle> Subheader </v-card-subtitle> <v-spacer></v-spacer> <router-link v-if="type == 'index'" :to="`/${name.toLowerCase().replace(' ', '-')}/create`"> <v-btn outlined class="blue--text mt-5 mr-8"> <span>Create</span> </v-btn> </router-link> </v-card> </v-row> </template> <script> export default { props: { icon: String, name: String, title: String, subtitle: String, type: String }, components: {} } </script> <style scoped></style> 如果我将 <router-link> 移至 <v-card-subtitle> 我明白了 如果我将 <router-link> 移至 <v-card-title> 我明白了 有人可以帮我推一下吗? 小提琴 https://jsfiddle.net/bheng/h2u870dv/ 如果我这样做: <v-row class="pl-5"> <v-card-title> <span class="material-icons"> favorite_border </span> <p class="font-weight-bold">TITLE</p> <p class="caption">ST</p> </v-card-title> <v-spacer></v-spacer> <v-btn>Create</v-btn> </v-row> 我明白了 按钮似乎位于我想要的位置,但标题和副标题严重错位。我现在被困住了。 您可以在 v-row 中添加 div 或 v-col 并使用 css 按照您想要的方式对齐项目: new Vue({ el: '#app', vuetify: new Vuetify(), data() { return { icon: 'favorite_border', name: 'link', title: 'TITLE', subtitle: 'https://fonts.google.com/icons?selected=Material+Icons', type: 'index' } } }) .myclass { width: 100%; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; } <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Material+Icons" rel="stylesheet"> <div id="app"> <v-app> <v-main> <v-container> <v-row class="pl-5"> <div class="myclass"> <v-card class="pl-5 mycard" elevation="0"> <v-card-title> <v-icon left x-large color="primary">{{ icon }}</v-icon> <span class="font-weight-bold">{{ title }}</span> </v-card-title> <v-card-subtitle> Subheader </v-card-subtitle> <v-spacer></v-spacer> </v-card> <a v-if="type == 'index'" :href="`/${name.toLowerCase().replace(' ', '-')}/create`"> <v-btn outlined class="blue--text mt-5 mr-8"> <span>Create</span> </v-btn> </a> </div> </v-row> </v-container> </v-main> </v-app> </div> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script> 您的问题是您将按钮放置在您声明设置标题样式的v-card内。由于您没有指定任何宽度,因此这张卡只是一个方形盒子。如果你设置海拔=“1”,你可以清楚地看到这一点。 只需将按钮放在 v 卡外部,v-spacer 即可工作。或者,您也可以将 v-card 宽度设置为 100%。顺便说一句,您还可以在 to 中使用 v-btn 属性,因此不需要 v-router-link。 检查我制作的这个codesandbox:https://codesandbox.io/s/stack-71444864-v-spacer-example-0tx24n?file=/src/components/Example.vue <v-row class="pl-5"> <v-card class="pl-5" elevation="0"> <v-card-title> <v-icon left x-large color="primary"> mdi-home </v-icon> <span class="font-weight-bold">Testing</span> </v-card-title> <v-card-subtitle class="pb-0"> Subheader </v-card-subtitle> </v-card> <v-spacer></v-spacer> <v-btn to="/about" outlined class="blue--text mt-5 mr-8"> <span>Create</span> </v-btn> </v-row> 更新:v-cols 和带有断点条件的自定义 CSS 我看到您有兴趣学习如何使用 vuetify 的网格 进行此设计。使用 v-cols 和断点条件的优点是,您可以更好地控制不同视口的设计。就像在移动视图上一样。我就是这样做的。 我首先将网格分成两列,一列用于标题,一列用于按钮,在 cols 视图(以前称为 xs(超小))中,我将它们的大小设置为 12 列,然后在 sm(小)及以上,我将大小设置为每列 6 列。这样它们就显示为一半。 标题列没有变化,在按钮列上,我使用类 d-flex justify-end 将按钮全部移至右侧,并使用 align-center 将按钮垂直居中于 v-row 的中间。 然后,我使用断点条件来激活按钮的 block 属性,并将填充应用于整个 v 行,具体取决于当前视口。 <v-row :class="$vuetify.breakpoint.smAndUp ? 'px-4' : ''"> <v-col cols="12" sm="6"> <v-card elevation="0"> <v-card-title> <v-icon left x-large color="primary"> mdi-home </v-icon> <span class="font-weight-bold">Testing</span> </v-card-title> <v-card-subtitle class="pb-0"> Subheader </v-card-subtitle> </v-card> </v-col> <v-col cols="12" sm="6" class="d-flex justify-end align-center"> <v-btn to="/about" :block="$vuetify.breakpoint.xsOnly ? true : false" outlined class="blue--text"> <span>Create</span> </v-btn> </v-col> </v-row> 您正在使用 Vuetify 对吗?然后更简单,只需在 v-card-title 标签中添加带有绝对右上属性的按钮即可。然后 v-btn 还允许 :to (https://v2.vuetifyjs.com/en/api/v-btn/#props) <v-card-title> <v-icon left x-large color="primary">{{ icon }}</v-icon> <span class="font-weight-bold">{{ title }}</span> <v-btn outlined absolute right top v-if="type === 'index'" class="blue--text mt-5 mr-8" :to="name.toLowerCase().replace(' ', '-') + '/create'"> </v-btn> </v-card-title> <v-card-title class="d-flex justify-space-between"> <v-icon left x-large color="primary">{{ icon }}</v-icon> {{ title }} <span><v-btn outlined class="blue--text mt-5 mr-8"> Create </v-btn></span> </v-card-title>
我希望每次我的模拟更改并传递到数据时,条形图都可以重新渲染或更新。我在条形图组件中查看了 dataa,但它不起作用。 “console.log('这个', this.dataa);”永远不会触发...
我正在尝试在 vue-3 应用程序中实现布局。 基于这个解决方案,我创建了一个简单的布局文件: AppLayoutDashboard.vue: 我正在尝试在 vue-3 应用程序中实现布局。 基于这个解决方案,我创建了一个简单的布局文件: AppLayoutDashboard.vue: <template> <div style="border: 2px solid red"> <h1>AppLayoutDashboard.vue</h1> <slot/> </div> </template> 为了在某些视图中使用它,我: HomeView.vue: <template> <app-layout-dashboard> <!-- VIEW CODE HERE --> </app-layout-dashboard> </template> 我想让它更灵活,并将其移至App.vue。如果我直接将 <app-layout-dashboard> 标签移动到此文件,一切都会正常工作。 但是,我希望它能够动态加载。为了做到这一点,我想向路由数组添加一个新属性: const routes = [ { path: '/', name: 'home', component: HomeView, meta:{ layout: 'AppLayoutDashboard', } }, 我尝试使用<component :is="layout">(我从路由中检索layout),但它不起作用。 有什么建议吗? 我遇到了与您所描述的类似的问题,我发现这篇文章非常有用。 您不需要直接在每个页面或视图上插入布局。相反,创建一个容器布局: // src/layouts/AppContainerLayout.vue <template> <component :is="this.$route.meta.layoutComponent"> <slot /> </component> </template> <script> export default { name: "AppContainerLayout" } </script> 然后,更新您的 App.vue 文件以包含容器布局: // src/App.vue <script setup> import AppContainerLayout from './layouts/AppContainerLayout.vue'; </script> <template> <AppContainerLayout> <RouterView /> </AppContainerLayout> </template> 接下来,您可以按照您所描述的方式设置路由器,但现在您可以添加对中间件的调用以加载先前与所选路由关联的布局: // src/router/router.js import { createRouter, createWebHistory } from "vue-router"; import { loadLayoutMiddleware } from "./middleware/loadLayoutMiddleware"; import HomeView from "../views/HomeView.vue"; import AnotherView from "../views/AnotherView.vue"; import NotFoundView from "../views/NotFoundView.vue"; const routes = [ { path: "/", name: "Home", component: HomeView, meta: { layout: "AppLayoutDashboard", }, }, { path: "/another_view", name: "Another", component: AnotherView, }, { path: "/:pathMatch(.*)*", name: "NotFound", component: NotFoundView, meta: { layout: "AppLayoutError", }, }, ]; const router = createRouter({ history: createWebHistory(), routes, }); router.beforeEach(loadLayoutMiddleware); export default router; 这是我在同一篇文章的存储库中找到的与路由器关联的布局中间件,并进行了较小的更新,以在路由中未声明布局时加载默认布局: // src/router/middleware/loadLayoutMiddleware.js export async function loadLayoutMiddleware(route) { try { let layout = route.meta.layout || "DefaultLayout"; let layoutComponent = await import(`@/layouts/${layout}.vue`); route.meta.layoutComponent = layoutComponent.default; } catch (e) { console.error("Error occurred in processing of layouts: ", e); console.log("Mounted DefaultLayout"); let layout = "DefaultLayout"; let layoutComponent = await import(`@/layouts/${layout}.vue`); route.meta.layoutComponent = layoutComponent.default; } } 检查运行正常后即可取出日志。 请记住清除视图中对布局的任何引用 // src/views/HomeView.vue: <template> <!-- VIEW CODE HERE --> </template> 最后,此时唯一缺少的是创建自定义布局,但您已经涵盖了: // src/layouts/AppLayoutDashboard.vue <template> <div style="border: 2px solid red"> <h1>AppLayoutDashboard.vue</h1> <slot/> </div> </template> // src/layouts/DefaultLayout.vue <template> <div style="border: 2px solid red"> <h1>DefaultLayout.vue</h1> <slot/> </div> </template> // src/layouts/AppLayoutError.vue <template> <div style="border: 2px solid red"> <h1>AppLayoutError.vue</h1> <slot/> </div> </template>
我想在父组件中触发事件时调用子组件中的方法,我已经做了研究,这似乎是在脚本设置中执行此操作的共识方法: // 父组件 <
Vue 3 将 Quill 编辑器 Delta 对象的输出转换为 Html 并显示 Html
我正在设计一个应用程序,用户可以使用富文本编辑器进行评论,并且这些评论会显示为 html 对象。 这是获取评论的代码: 我正在设计一个应用程序,用户可以使用富文本编辑器进行评论,并且这些评论会显示为 html 对象。 这是接受评论的代码: <quill-editor theme="snow" v-model:content="newComment"></quill-editor> 地点: const newComment = ref('') 现在假设我想显示评论(同时考虑输入的所有功能,例如项目符号点或粗体文本),我有这个元素 <div v-html="newComment"></div> 但是这个div的输出是[object Object],不是我预期的。或者,如果我写 <div>{{newComment}}</div> 我只会得到一个像 { "ops": [ { "insert": "aaa\n" } ] } 这样的 Delta 对象。 我阅读了文档和类似的代码。有一些现有代码,但我找不到 Vue 3 组合 API 案例。 您必须指定内容类型。 <quill-editor theme="snow" v-model:content="newComment" content-type="html"></quill-editor> 它会起作用的
{{停止}} ... <template> <div> <v-container fluid id="main"> <v-card class="white lighten-4 elevation-3"> <li v-for="stop in stop_name_arr"> {{stop}} </li> <direct_bus_travel_time_in_between_stops> </direct_bus_travel_time_in_between_stops> <direct_bus_travel_distance_in_between_stops> </direct_bus_travel_distance_in_between_stops> </v-card> </v-container> </div> </template> 我有两个组件direct_bus_travel_time_in_between_stops和direct_bus_travel_distance_in_between_stops要在<li v-for="stop in stop_name_arr">{{stop}}</li>完全执行后加载。 有什么方法可以将组件动态附加到函数内,以便在我想要加载它时加载它吗? 我非常认为您可以使用元 component 标签,该标签异步加载传递给 is 属性的给定组件。 这是代码: <component is="direct_bus_travel_time_in_between_stops" > </component> <component is="direct_bus_travel_time_in_between_stops" > </component> 您可以在此标签中添加功能/事件,它将在何种条件下加载。 我认为这个链接会有帮助 - https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components 其中描述了动态使用的绑定组件 希望我的方法对你有用! 更新:这个答案是参考 vue 2.x 版本提供的。我不知道 vue 3.x,也没有阅读 3.x 文档。您可以随时提交 vue 3.x 兼容解决方案的编辑草稿。谢谢! 我已经准备了类似的方法,但更加自动化,使用由 pinia 提供支持的 localStorage 和包装器组件,一次切换所有实例。 看看并随意发表评论:) https://github.com/Nagell/dynamic_loading_components
我刚刚发现在 Vue3 中,v-model 不能与子组件响应式/反应式地工作。 此代码将更新用户名数据 我刚刚发现,在 Vue3 中,v-model 无法与子Component做出响应式/反应式工作。 此代码将更新username数据 <template> <div> <input type="text" v-model="username" placeholder="Insert your username" /> <p>{{ username }}</p> </div> </template> <script> // Home.vue export default { name: 'Home', data() { return { username: 'admin' } } } </script> 如果我在 input 中输入内容,username 数据也会改变。 但是,当我像这个例子一样使用 Component 时: <template> <input type="text" :class="'input-text ' + additionalClass" :placeholder="placeholder" /> </template> <script> // InputText.vue import { defineComponent } from "vue" export default defineComponent({ name: 'InputText', props: { placeholder: { type: String, default: '' }, additionalClass: { type: String, default: '' } } }) </script> 然后我更新了我的代码以使用 Component。 注意:Component已注册成功。 <template> <div> <input-text v-model="username" :placeholder="`Insert your username`" /> <p>{{ username }}</p> </div> </template> <script> // Home.vue export default { name: 'Home', data() { return { username: 'admin' } } } </script> 当我输入内容时,username数据没有更新,与之前的不同。 有什么解决方案或至少参考我想要实现的目标吗? 使用 Vue3 script setup 语法 <template> <input type="text" v-model="val" @input="handleInput"> </template> <script setup> import {ref, defineProps, defineEmits, watch} from 'vue' const props = defineProps({ modelValue: { type: String, default: '' }, }) const emit = defineEmits(['update:modelValue']) const val = ref('') watch(() => props.modelValue, nVal => val.value = nVal, { immediate: true }) const handleInput = () => emit('update:modelValue', val.value) </script> 您不能指望 v-model 为您隐式更新底层元素。换句话说,您仍然需要在组件本身内处理该问题,并公开 modelValue 作为其真正起作用的道具。类似这样的东西: <template> <input type="text" @input="onChanged" :value="modelValue" :class="'input-text ' + additionalClass" :placeholder="placeholder" /> </template> <script> // InputText.vue import { defineComponent } from "vue" export default defineComponent({ name: 'InputText', emits: ['update:modelValue'], props: { modelValue: String, placeholder: { type: String, default: '' }, additionalClass: { type: String, default: '' } }, setup(props, { emit }) { function onChanged(e) { emit('update:modelValue', e.currentTarget.value); } return { onChanged } } }) </script> VueUse 助手 useVModel 可以简化子组件中的 v-model 处理,请参阅 https://vueuse.org/core/usevmodel/#usage <script lang="ts" setup> import { useVModel } from '@vueuse/core' const props = defineProps<{ modelValue: string }>() const emit = defineEmits(['update:modelValue']) const model = useVModel(props, 'modelValue', emit) </script> <template> <input type="text" v-model="model" /> </template> 使用 OPTIONS API 语法 <template> <input type="text" v-model="val" @input="updateText" :value="modelValue"> </template> <script scoped> export default { props: { modelValue: String, }, methods: { updateText(event){ this.$emit('update:modelValue', event.currentTarget.value) } } } </script> 从 vue 3.4 开始推荐的方法是使用 defineModel() 宏。 https://vuejs.org/guide/components/v-model 根据您的回答,代码将如下所示(使用 TypeScript 类型): <script setup lang="ts"> const model = defineModel(); const { placeholder, additionalClass } = defineProps<{ placeholder: string additionalClass: string }>(); </script> <template> <input type="text" v-model="model" :class="'input-text ' + additionalClass" :placeholder="placeholder" /> </template> 在你的父组件中 <script setup lang="ts"> const textInput = ref(''); </script> <template> <SomeInput v-model="textInput" placeholder="placeholder" additionalClass="some-class" /> </template> 在vue2中,这个东西起作用了: 您的InputText组件 <template> <input :value="value" @input="({target}) => $emit('input', target.value)"/> </template> <script> export default { props: { value: {} } } 您的父组件 <template> <inputText v-model="inputValue"/> </template> <script> export default { components: {inputText}, data: () => ({ inputValue: null }) } </script>
我是 vue js 初学者。我正在尝试从 vue 官方文档中逐步学习。我尝试了解组件功能并创建了以下代码: 我是 vue js 初学者。我正在尝试从 vue 官方文档中逐步学习。我尝试了解组件功能并创建了以下代码: <div id="app"> <table class="table"> <tr> <td><strong>Name</strong></td> <td><strong>Email Address</strong></td> </tr> <contact-item v-for="item in contacts" v-bind:contact="item" v-bind:key="item.id"></contact-item> </table> </div> 这是用于显示组件模板中的行数据的 JavaScript 代码。 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> Vue.component('contact-item', { props: ['contact'], template: '<tr><td>{{ contact.name }}</td><td>{{ contact.email }}</td></tr>' }) var app = new Vue({ el: '#app', data: { contacts: [ {id: 1, name:'John Doe', email:'[email protected]'}, {id: 2, name:'Peter Drunket', email:'[email protected]'}, {id: 3, name:'Mike Benjamin', email:'[email protected]'}, ] } }); </script> 问题是数据正在显示,但不在表格中。它显示在“app”div 之后。 附输出截图。 如果 DOM 模板混合了 Vue 组件和原生元素,则解析 DOM 模板时有某些警告。 一些 HTML 元素,例如 <ul>、<ol>、<table> 和 <select> 具有 对哪些元素可以出现在其中的限制,以及一些 <li>、<tr>、<option>等元素只能出现在内部 某些其他元素。 当使用具有以下元素的组件时,这会导致问题 这样的限制。例如: <table> <blog-post-row></blog-post-row> </table> 自定义组件将被视为无效而被吊出 内容,导致最终渲染输出出现错误。 在您的情况下,它导致您的表格呈现在标题“上方”。实际上,在这种情况下,浏览器创建了两个表:一个用于 <tr> 替换提升的组件,另一个用于从一开始就存在于模板中的“本机”表。 幸运的是,is特殊属性提供了一种解决方法。您需要指定要用来替换特定本机元素的组件的名称。两次指定该元素的名称不太方便(首先在 HTML 中,然后在组件本身中),但是,正如前面所说,这是一种解决方法。 <table> <tr is="blog-post-row"></tr> </table> 您的情况可能如下: Vue.component('contact-item', { props: ['contact'], template: '<tr><td>{{ contact.name }}</td><td>{{ contact.email }}</td></tr>' }) var app = new Vue({ el: '#app', data: { contacts: [{ id: 1, name: 'John Doe', email: '[email protected]' }, { id: 2, name: 'Peter Drunket', email: '[email protected]' }, { id: 3, name: 'Mike Benjamin', email: '[email protected]' }, ] } }); <div id="app"> <table class="table"> <tr> <td><strong>Name</strong></td> <td><strong>Email Address</strong></td> </tr> <tr is="contact-item" v-for="item in contacts" v-bind:contact="item" v-bind:key="item.id"></tr> </table> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> 这个解决方法也会对您有帮助 引入不执行任何操作的自定义表格组件: Vue.component('my-table', { props: [''], emits: [], mounted: function () { }, data: function () { return { } }, methods: { }, template: '<table>' + '<slot></slot>' + '</table>' }) 只需使用此组件而不是本机“table”标签 <div id="app"> <my-table class="table"> <tr> <td><strong>Name</strong></td> <td><strong>Email Address</strong></td> </tr> <contact-item v-for="item in contacts" v-bind:contact="item" v-bind:key="item.id"></contact-item> </my-table> </div>
我在 vue.js 项目中使用 vue-multiselect 组件,我使用 v-on 指令在更改事件上执行函数, 我在 vue.js 项目中使用 vue-multiselect 组件,我使用 v-on 指令在更改事件上执行函数, <multiselect v-model="selected" :options="projects" :searchable="false" :custom-label="customLabel" track-by="name" v-on:change="executeLoader"> <template slot="customLabel" slot-scope="{ customLabel }"><strong>{{ option.name }}</strong></template> </multiselect> 我这里有完整的示例代码:https://codesandbox.io/s/yjjon0vzxj v-on:change 正在与 <select> 组件一起工作,但它停止与 vue-multiselect 一起工作!我尝试过 v-on:click="executeLoader" 但这也不起作用.. @click 不会用 vue multiselect 触发方法 executeLoader。 您可以使用 @input - 类似于 v-on:change、@close、@select,如下例所示: <multiselect placeholder="Pick at least one" select-label="Enter doesn’t work here!" :value="value" :options="options" :multiple="true" :searchable="true" :allow-empty="false" :hide-selected="true" :max-height="150" :max="3" :disabled="isDisabled" :block-keys="['Tab', 'Enter']" @input="onChange" @close="onTouch" @select="onSelect"> </multiselect> 对于你的情况我会尝试@input="executeLoader" 在 vue-multiselect 中,由于它是一个组件,因此您不能将其视为简单的 <select> 元素。 在组件中,当您希望它们像其他 html 标签一样表现并“监听”单击事件时,您应该添加一个名为:.native的事件修饰符。 因此,您可以在任何组件上执行以下操作: <... @click.native="executeLoader" /> 但我认为这不是你正在寻找的。您希望在添加越来越多的标签时触发一个函数,或者简而言之:当所选项目增加时触发一个函数。 为此,vue-multiselect 公开了 @input 事件,因此您可以使用以下方式处理: <... @input="executeLoader" /> 现在只需调用 executeLoader 并接受参数: methods: { executeLoader(selectedItems) {} } 如果您在 2024 年阅读本文,您可能正在使用 Vue 3,所以请尝试 <multiselect ... @update:model-value="apply" />
我的父组件中有以下代码: 我的父组件中有以下代码: <TestVIsComponent :post="somepost" :somevalue="17" data-status="activated" data-feature="new" @change="submitChange"></TestVIsComponent> 以及以下子组件: <div> <h1 v-bind="$attrs">{{post.id}}</h1> </div> 此代码和 $attrs 会将 data-status="activated" data-feature="new" 属性传递给 H1 标签,而不是所需结果的 div。这是结果: <h1 data-status="activated" data-feature="new">1</h1> 但是,有没有办法只将一个属性传递给H1标签呢?有没有办法以某种方式迭代孩子中的 $attrs ?像 attrs[0] 或 attrs['attribute_name'] 这样的东西?我需要实现以下或类似目标: <div> <h1 v-bind="$attrs[0]">{{post.id}}</h1> <h3 v-bind="$attrs[1]">{{post.something}}</h3> </div> 如果您知道 div 元素的属性,那么您应该将它们用作 props 而不是 $attrs。 或者你可以分开$attrs <template> <div v-bind="divAttrs"> <h1 v-bind="h1Attrs">{{post.id}}</h1> </div> </template> <script> export default { computed: { divAttrs () { const allowed = ['data-status', 'data-feature'] return Object.keys(this.$attrs) .filter(key => allowed.includes(key)) .reduce((obj, key) => { obj[key] = this.$attrs[key] return obj }, {}) }, h1Attrs () { const notAllowed = ['data-status', 'data-feature'] return Object.keys(this.$attrs) .filter(key => !notAllowed.includes(key)) .reduce((obj, key) => { obj[key] = this.$attrs[key] return obj }, {}) } } } </script> 这就是我有条件地传递 $attrs 的方式。我有一个动态组件,它可以接受不同的 props,具体取决于它渲染的实际组件。 componentToRender是一个计算值,它可能是'a'(标签)或'RouterLink'(vue路由器RouterLink组件)。 当它渲染标签时,我想传递道具href。 当它渲染 RouterLink 时,我不想传递 props href。 <component :is="componentToRender" v-bind="{ ...$attrs, ...(componentToRender === 'a' ? { href: newLink } : {}) }"> Go to the link </component>
即使在等待nextTick之后也必须使用setTimeout?
我正在尝试观察一个计算值,该值被来自商店的消息填满。就是这样(为简洁起见,减少了代码): ... 我正在尝试 watch 一个计算值,该值被来自商店的消息填充。就是这样(为简洁起见,减少了代码): <div ref="RefWindow"> <!-- Messages shown here --> </div> const Feed = computed(() => MyStore.Messages) const RefWindow = ref(); function scrollToBottom() { console.log(`scrollTop: ${RefWindow.value.scrollTop}, scrollHeight: ${RefWindow.value.scrollHeight}`) RefWindow.value.scrollTop = RefWindow.value.scrollHeight; // Scrolls to bottom } watch(() => Feed, async () => { await nextTick(); scrollToBottom(); // Doesn't work console.log shows scrollTop: 0, scrollHeight: 0 setTimeout(()=> scrollToBottom(), 20); // Works console.log shows scrollTop: 0, scrollHeight: 4203 } }, { immediate: true, deep: true }) 据我了解,nextTick()几乎就像onUpdated生命周期挂钩一样,一旦Feed的值发生更改,在下一次更新 DOM 时,代码应该运行。然而,如果没有 setTimeout,div scrollHeight 的 RefWindow 似乎不会被更新。 不使用超时的正确方法是什么? 由于您没有提供完整的模板和更好的 MRE,因此不清楚会发生什么。 您可以尝试手表的flush: 'post'选项: https://vuejs.org/guide/essentials/watchers#post-watchers
我想检查子组件是否已安装,并且我想将该信息移动到父组件。为此,我正在使用发射。 因此,这里的示例是我的父组件: 我想检查子组件是否已安装,并且我想将该信息移动到父组件。为此,我正在使用发射。 因此,这里的示例是我的父组件: <child @is-child-mounted="childMounted" /> export default { data() { return { childMounted: false, }; }, mounted() { if (this.childMounted) { //do something } }, } 在子组件中,我将“is-child-mounted”更改为 true: mounted() { this.$emit('isChildMounted', true); }, 但是 if (this.childMounted) 仍然为假。那么如果子组件已挂载,如何检查父组件呢? 您可以在父组件的子组件上添加监听器。它看起来像这样: Vue3 <Component @vnodeMounted="handleMounted" /> Vue2 <Component @hook:mounted="handleMounted" /> 您可以将钩子名称替换为您想要收听的生命周期名称!我想它应该很少使用,因为它没有出现在文档中,因此是一个内部 API,注定不能直接使用。 来源: https://github.com/vuejs/core/issues/4345#issuecomment-899082892 https://github.com/vuejs/vue/blob/8d3fce029f20a73d5d0b1ff10cbf6fa73c989e62/src/core/instance/lifecycle.js#L348 在触发事件时,子组件中的事件名称似乎有拼写错误,否则代码应该可以正常工作。 应该是is-child-mounted而不是ischildmounted 应该是@is-child-mounted="childMounted = true"而不是@is-child-mounted="childMounted" 现场演示: Vue.component('child', { props: ['childmsg'], template: '<p>{{ childmsg }}</p>', mounted() { this.$emit('is-child-mounted') } }); var app = new Vue({ el: '#app', data: { childMounted: false }, mounted() { if (this.childMounted) { console.log('child mounted'); } } }); <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <child childmsg="This is a child component" @is-child-mounted="childMounted = true"></child> </div> Vue3 现在你需要使用 @vue:mounted 代替(@hook:mounted 之前)。 例如 <template> <child @vue:mounted="childMounted()"/> </template> 请参阅 Vue 3 迁移指南 - VNode 生命周期事件了解详细信息 另外,请记住,一些事件名称如 destroyed 和 beforeDestroy 在 Vue3 中已分别重命名为 unmounted 和 beforeUnmount
我想从父组件获取 vue.js 组件的尺寸(我正在使用实验脚本设置)。 当我在组件内使用 ref 时,它会按预期工作。我知道尺寸了...
我试图在我的笔记本应用程序中使用 vuedraggable,当我添加可拖动组件时出现此错误。这是代码和错误。我将不胜感激的帮助。 这是错误
我正在寻找将一个大学项目翻译成其他语言,所以我查找了一些方法,并找到了 I18n。我使用 npm install vue-i18n@10 将其安装在项目的根目录中。 我确实...
[Vue warn]:无法解决组件:v-toolbar-title问题vue3和vuetify 3.0.0-alpha.0版本
我在使用以下配置运行示例应用程序时遇到以下问题。 包.json > "vue": "^3.0.0", > "vue-textarea-autosize": "^1.1.1&...
我在我的 Vue 项目中面临着下面描述的挑战,并且对该怎么做感到非常困惑。 有一个名为“button-base”的单子组件: 我在我的 Vue 项目中面临着下面描述的挑战,并且对该怎么做感到非常困惑。 有一个名为 button-base 的单子组件: <template> <button :type="buttonType" :class=" { primary_button: buttonClass == 'primary', secondary_button: buttonClass == 'secondary', tertiary_button: buttonClass == 'tertiary', large: large, medium: medium, small: small, xsmall: xsmall, iconName: iconName }" > <div class="text_wrapper"> <span v-if="iconName" class="icon material-icons">{{ iconName }}</span> {{ buttonText }} </div> </button> </template> <script> export default { props: [ "buttonText", "buttonType", "buttonClass", "large", "small", "xsmall", "iconName" ] } </script> 在父组件(feed-card)上使用它,如下所示: <template> <div class="sub_options_left_side"> <button-base buttonType="button" buttonClass="tertiary" :iconName="idCopyIconName" :buttonText="idCopyButtonText" xsmall="xsmall" class="feed_card_option_button" @click="copyId" ></button-base> </div> </template> <script> export default { props: [ //some oter props.. "idCopyIconName", "idCopyButtonText" ], emits: ["copyId"], data() { return { //other unrelated data info.. } }, methods: { copyId() { this.$emit("copyId"); } }, //other stuff.. </script> 上面的组件也是这个最终组件下的子组件(feed-page): <template> <div class="feeds_wrapper_feed_container"> <feed-card v-for="feed in feedList" :key="feed.id" <!-- other props --> :id-copy-icon-name="idCopyIconName" :id-copy-button-text="idCopyButtonText" @copy-id="copyId(feed.id)" ></feed-card> </div> </template> <script> //imports.. export default { //components.. data() { return { idCopyButtonText: "ID", idCopyIconName: "file_copy" } }, methods: { copyId(docId) { //some other stuff copying parameter to clipboard.. this.idCopyIconName = "check"; this.idCopyButtonText = ""; } } </script> 事情是这样的:当用户单击最终触发该 copyId 方法的按钮时,我想更改该按钮的图像并删除其文本以改进一些用户体验 但是仅 that 按钮的图像和文本。 当我按照我展示的方式进行操作时,所有button-base图标和文本都会受到影响,包括未单击的图标和文本,因为它们以相同的v-for迭代。 我应该如何重新构建我的道具和组件来实现我正在寻找的东西。 提前致谢。 您可以按照自己喜欢的方式构建组件,但重要的是要记住 Vue 依赖于数据。并且您的数据应该始终沿着结构向下流动(从父组件到子组件),并且事件可以从子组件上升到父组件,例如,更改父组件中的数据,然后将更新的数据分发到需要它的子组件. 在下面的示例中,数据驱动修改按钮的 css 类。 <base-button :button-text="read ? 'readed' : 'read'" :read="read" @copy-id="$emit('copy-id')"></base-button> 更改仅涉及与我们当前按下的按钮相关的数据。在父组件中,我们找到与该按钮相关的条目,并将其状态更改为“已读”。 copyId(docId) { const indexItemClick = this.list.findIndex(x => x.id === docId); if (indexItemClick !== -1) { this.list[indexItemClick].read = !this.list[indexItemClick].read; } } 之后数据通过 props 传递给子组件,并根据此进行渲染。 ... app.component('base-button', { props: ['type', 'buttonText', 'read'], ... 完整的工作示例。 const app = Vue.createApp({ data() { return { list: [{ id: 1, text: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. ', read: false }, { id: 2, text: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. ', read: false } ] } }, methods: { copyId(docId) { const indexItemClick = this.list.findIndex(x => x.id === docId); if (indexItemClick !== -1) { this.list[indexItemClick].read = !this.list[indexItemClick].read; } } } }) app.component('base-button', { props: ['type', 'buttonText', 'read'], emit: ['copy-id'], template: ` <button type="button" :class="[read ? 'primary_button' : 'secondary_button']" @click="$emit('copy-id')"> <div class="text_wrapper"> {{ buttonText }} </div> </button> ` }) app.component('feed-card', { props: ['text', 'read'], emit: ['copy-id'], template: ` <div> <p>{{ text }}</p> <base-button :button-text="read ? 'readed' : 'read'" :read="read" @copy-id="$emit('copy-id')"></base-button> </div> ` }) app.mount('#app') .primary_button { background: red; } .secondary_button { background: green; } <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script> <div id="app"> <feed-card v-for="l in list" :key="l.id" :read="l.read" :text="l.text" @copy-id="copyId(l.id)"></feed-card> </div> 抱歉我的英语不好)
我正在开发一个Vue应用程序。 它有一个标题,然后是主要内容。 嵌套和结构如下 TheHeader.vue -> TheLogin.vue MainContent.vue -> ShoppingCart.vue -> OrderSumm...
Vuetify 3 在单击或悬停时在按钮、v-menu、v-select 和其他组件上提供深色背景
我正在使用 Vue ^3.2.13 和 Vuetify ^3.3.17。每当我使用 v-btn 或 v-menu 或 v-select 时,所选项目上都会出现深色背景。 像这样 这是我的 vuetify.ts 文件: 导入{createVuet...