My problem:
I can't split vue.js code into chunks, I have tried a lot of examples from tutorials. When I am trying to not load vue component with app and split it, for example, with v-if="show_component", got an error component included, but not used. I don't know how to split code and use components, when they needed. In practice, there are no any working examples.
Example of the problem with vue-js-modal:
Can't divide modals into loadable chunks.
I need to load modals only when they triggered to open. It will shrink first page load size. But this option is impossible. Here is my modals structure:
/src/components/Modals/ExampleModal.vue
<template>
<modal name="examplemodal" class="examplemodal-modal" :adaptive="true" :max-width="450">
<div class="header row">
<h3>Title is here</h3>
<v-icon name="times" />
</div>
<div class="content col">
<p>
<b>Some content</b>
<br /><br />
More text here...
</p>
</div>
</modal>
</template>
<style lang="scss">
.examplemodal-modal {
background: rgba(9, 15, 30, 0.3);
.vm--modal {
// I got here a lot of styles in modals
}
}
</style>
/src/main.js
import Vue from 'vue';
import App from './App';
import Icon from 'vue-awesome/components/Icon';
import VModal from 'vue-js-modal';
Vue.component('v-icon', Icon);
/* Tried to make loadable modals, divided to chunks */
Vue.use(VModal, { dynamic: true, injectModalsContainer: true });
Vue.config.productionTip = false;
new Vue({
store,
render: h => h(App),
}).$mount('#app');
/src/App.vue
<template>
<div id="app">
<modals-container />
<button class="btn green" #click="showModal">
Show modal
</button>
</div>
</template>
<script>
import ExampleModal from './components/ExampleModal.vue';
export default {
name: 'App',
methods: {
showModal() { this.$modal.show(ExampleModal ) } // Shows empty modal
}
};
</script>
Modal still don't divided into loadable chunks.
If you got any ideas, please, help me.
Version of vue-js-modal:
^2.0.0-rc.3
I have checked stackoverflow for solutions and 100% sure that this issue is not not related to my code.
Webpack has an optimization
Webpzck optimization
Here is en example:
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
minSize: 10000,
maxSize: 250000,
}
}
}
}
If you have a test folder, you should set
test: /[\\/]node_modules[\\/]/,
or your tests can't bundle and run.
Related
Every time I use Nuxt.js in my projects I encounter the same mistake with styles. Some of them are enabled after the page is mounted. I tried to import styles from a file from a static folder, tried to use styles in the file (tag style), with the scoped attribute, without it, but each time some styles are included after the page has already been mounted. There are no problems in pure Vue js.
Look here, this is the state I was talking about. It lasts about half a second
And after that the page becomes normal
Sometimes this state persists until the user scrolls the page, sometimes it does not disappear at all
To clarify, I prefer the scoped attribute in my projects, without importing files with styles.
Edit
Ok. I don't know will it helps, but there is the code snippets
This is a test page
<template>
<div>
<app-promo
:data="{
titles: ['адреса пиццерий', 'roni napoletana'],
bgImg: 'page-addresses/promo/promo_bg.png'
}"
>
<app-search></app-search>
</app-promo>
</div>
</template>
This is a search component
<template>
<div v-click-outside="closeResults" class="search">
<div class="search__bar">
<input placeholder="Начните вводить название улицы, чтобы найти ближайшую пиццерию" v-model="searchRequest" #keypress.enter="search" type="text" class="search__input">
<button #click="search" class="search__submit"><img src="#/static/img/page-addresses/promo/zoom.svg" alt="Search"></button>
</div>
<div :class="['search__results', {'search__results_active': showResults}]">
<nuxt-link
:to="item.link"
class="search__result"
v-for="item in searchedItems"
:key="item.title"
>
{{ item.title }}
</nuxt-link>
</div>
</div>
</template>
<script>
export default {
data() {
return {
searchedItems: [
{
title: 'Истикбол улица',
link: '/'
},
{
title: 'Шевченко улица',
link: '/'
},
{
title: 'Тараккиёт улица',
link: '/'
}
],
searchRequest: '',
showResults: false
}
},
methods: {
search() {
this.showResults = true
},
closeResults() {
this.showResults = false
}
},
}
</script>
This is a promo component
<template>
<section class="promo">
<div class="promo__bg"><img src="#/static/img/page-main/promo/promo_bg.png" alt=""></div>
<div class="promo__inner">
<h1 class="promo__title">
<template v-for="title in data.titles">
{{ title }}
</template>
</h1>
<h2 class="promo__subtitle" v-if="data.subtitle">{{ data.subtitle }}</h2>
<slot></slot>
</div>
<div class="promo__label" v-if="data.labelImg">
<img src="#/static/img/page-main/promo/label_img.svg" alt="Img">
</div>
</section>
</template>
<script>
export default {
props: {
data: {
default: {
titles: '',
subtitle: '',
labelImg: '',
bgImg: ''
}
}
}
}
</script>
My nuxtconfig is standard. The styles are too.
I am trying to use react-id-swiper in my project. I am just following the examples as shown in this website: https://react-id-swiper.ashernguyen.site/example/navigation.
For some reason the navigation buttons (Left and Right navigation arrow buttons) are not working for me. I even tried using the pagination, even that doesn't work.
This is the codesandbox that I created: https://codesandbox.io/s/peaceful-leftpad-9cgts?file=/src/App.js
Here's the code that I am using:
import React from "react";
import Swiper from "react-id-swiper";
import "swiper/swiper.scss";
import "swiper/components/navigation/navigation.scss";
import "swiper/components/pagination/pagination.scss";
import "./styles.scss";
const params = {
effect: "cube",
pagination: {
el: ".swiper-pagination",
clickable: true
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev"
}
};
const Slider = () => {
return (
<Swiper {...params}>
<div className="myslide">Slide #1</div>
<div className="myslide">Slide #2</div>
<div className="myslide">Slide #3</div>
<div className="myslide">Slide #4</div>
<div className="myslide">Slide #5</div>
</Swiper>
);
};
export default function App() {
return (
<div className="App">
<Slider />
</div>
);
}
I have the code examples taken from here: https://react-id-swiper.ashernguyen.site/example/navigation .
Can someone tell me what am I missing?
I got the solution of this issue,
the root cause are:
the version of react-id-swiper and swiper did not match each other
I fix this by using react-id-swiper#4.0.0 and swiper#6.0.4
need to import below packages
import Swiper from 'react-id-swiper';
import SwiperCore, { Pagination } from 'swiper';
import 'swiper/swiper-bundle.css';
and add this use code after import
SwiperCore.use([Pagination]);
I got the answer from here: https://github.com/kidjp85/react-id-swiper/issues/453#issuecomment-814500317
Hope this answer can help you.
I've faced the same issue.
The reason is that swiper#^6.4.5 is used. I don't know since what version exactly, but in 6.4.5 swiper has its own implementation of react components, which we have to use.
Refer to this page to understand how to use swiper's react implementation:
https://swiperjs.com/react/
I have faced this issue as well. Even after you import it you have to load the modules directly onto the component.
Follow the code below and it should work perfectly
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css/pagination"; // if yo want to style it
import { Navigation, Pagination} from "swiper";
const Slider = () => {
return (
<Swiper
modules={[Pagination]}//you can add any other module here such as navigation and whatever else
pagination={{ clickable: true }}
>
<div className="myslide">Slide #1</div>
<div className="myslide">Slide #2</div>
<div className="myslide">Slide #3</div>
<div className="myslide">Slide #4</div>
<div className="myslide">Slide #5</div>
</Swiper>
);
};
this is the structure of my project
src
components
create.vue
resume.vue
service.vue
shared
header.vue
menu.vue
loader.vue
footer.vue
this is my loader component
<template>
<div class="three col">
<!-- <div class="loader" id="spinner"></div> -->
<div class="loader" id="spinner-2">
<span></span>
<span></span>
<span></span>
</div>
</div>
</template>
<script>
export default {
name: 'Loader',
}
</script>
and I have it imported and running on my component create.vue
<template>
<div v-show="formInfo.selectedId != ''">
<h1 class="title">What's the name of your
<span>{{idName}}</span> ?
</h1>
<input
type="text"
class="form-control"
v-model="formInfo.name"
#keypress="onChangeName($event)"
#keyup="onChangeName($event)"
/>
<div class="loader-spinner" v-if="loading">
<ciev-app-loader>
</div>
</div>
</template>
<script>
import Loader from '../shared/loader.vue'
export default {
data() {
return {
step: 1,
specieName: "",
breedName: "",
animalName: "",
breedId: 0,
imageSelected: false,
isFormCompleted: false,
isBreedSelected: false,
loading: false,
isLoaderFinished: false,
myTimeout: 0
};
},
components: {
'ciev-app-loader': Loader
},
up to this point everything works fine, but now I want to reuse the component Loader in my component resume.vue.
I import it and declare it in the template as follows
<template>
<div
v-show="!displayUnknown"
class="column"
v-bind:class="{ paymentIsActive: 'payment' === selectedResume }"
#click="onClickResume('payment')"
>
<label>
<input
type="radio"
name="selectedResume"
value="payment"
v-model="selectedResume"
/>
<i class="icon-card"></i>
</label>
</div>
<div class="loader-spinner">
<ciev-app-loader />
</div>
</template>
<script>
import globalAxios from "axios";
import { isMobile } from "mobile-device-detect";
import Config from "./../../config.js";
import FileSaver from 'file-saver';
import { saveAs } from 'file-saver';
import Loader from '../shared/loader.vue'
export default {
data() {
return {
step: 3,
selectedResume: "",
selectedCremationService: null,
focusService: undefined,
selectedServicePrice: 0.0,
displayResume: false,
displayUnknown: false,
offer: "unknown",
isMobile: isMobile ? true : false,
};
},
components: {
'ciev-app-loader': Loader
},
</script>
The Loader component is not shown in the template, although inspecting elements in the browser does load it, and it returns me by console the following error
"[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option."
Looking at references to the same error, I have declared the name on the component porpio when exporting it, but I think I have already done it in the Loader.
What am I doing wrong?
Thank you all for your time and help in advance.
The root <div> seems to have closed incorrectly in the resume.vue component.
Correct it and try again.
<div
v-show="!displayUnknown"
class="column"
v-bind:class="{ paymentIsActive: 'payment' === selectedResume }"
#click="onClickResume('payment')"
>
<label>
<input
type="radio"
name="selectedResume"
value="payment"
v-model="selectedResume"
/>
<i class="icon-card"></i>
</label>
<div class="loader-spinner">
<ciev-app-loader />
</div>
</div>
checking my code carefully the error was that besides declaring in the script the components object with the declaration of the imported component I had declared it in duplicate at the end of the script as an empty object and this generated the error.
thanks for your help
I am currently creating a progressive web app with React, HTML, JS, and CSS for learning purposes and have run into an issue where my ExercisePanel components are displaying the exact same information despite being given 2 different objects to pull information from. The ExercisePanel is a stylized button that displays an image and the name of the exercise, and it accurately updates with the different objects. The problem stems from my custom Modal that I made to display the information, as it always displays the information of the first component listed in the App.js file. I have also cut down on some of the Strings for the sake of readability. The files below are what I believe are causing the problem, however I have been unable to figure out the cause. I apologize if the code is messy, I am a beginner with these tools. (Order is App.js then ExercisePanel.js then Modal.jsx)
// Import React and Component
import React, { Component } from 'react';
// Import CSS from App.css
import './App.css';
import Exercise from './js/classes/Exercise.js';
// Import the Today component to be used below
import ExercisePanel from './Components/ExercisePanel.js'
class App extends Component {
render() {
var test = new Exercise("Curl Ups", "10-30", "30 - 90", "A curl up (or sit up) ...", "Medium", "https://img.icons8.com/ios-glyphs/96/000000/sit-ups.png");
var test2 = new Exercise("TEST2", "ur", "2", "sda", "sad", "");
return (
<div className="">
<div className="topheader">
<header className="container">
<nav className="navbar">
<div className="navbar-brand">
<span className="navbar-item"><font class="topheader">Let's Move!</font></span>
</div>
</nav>
</header>
</div>
<section className="results--section">
<div className="container">
<h1>Let's Move is a Website ...</h1>
</div>
<div className="results--section__inner">
<ExercisePanel exercise={test}/>
<ExercisePanel exercise={test2}/>
</div>
</section>
</div>
);
}
}
export default App;
import React from 'react';
import ExerciseButton from './ExerciseButton';
import Modal from './Modal'
let ExercisePanel = (props) => {
return (
<div>
<ExerciseButton image={props.exercise.image} id={props.exercise.name} onClick={handleClick}>{props.exercise.name}</ExerciseButton>
<Modal desc={props.exercise.desc} clickEvent={handleClick} cal={props.exercise.calories} time={props.exercise.estTime} name={props.exercise.name} diff={props.exercise.difficulty}/>
</div>
);
}
function handleClick() {
document.querySelector('.modal').classList.toggle('modal--hidden');
}
export default ExercisePanel;
import React from 'react';
import "./ModalStyle.css"
var Modal = ({name, desc, cal, time, diff, clickEvent}) => {
return (
<div className="modal modal--hidden">
<div style={{backgroundColor: "#beb", padding: "2rem 4rem", maxWidth: "50%", borderRadius: "10px"}}>
<div className="close-button">
<button style={{border: "none", background: "none", cursor: "pointer"}} onClick={clickEvent}>X</button>
</div>
<div className="modal--header">
<span style={{fontWeight: "bold"}}>{name}</span>
</div>
<p>
{desc}
</p>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/ios-filled/50/000000/fire-element.png" alt="calorieImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Calories: " + cal}</span>
</div>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/pastel-glyph/50/000000/clock.png" alt="clockImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Recommended Time: " + time}</span>
</div>
<div>
<img style={{verticalAlign: "middle"}} src="https://img.icons8.com/android/40/000000/flex-biceps.png" alt="difficultyImg"/>
<span style={{fontSize: "1.5rem", verticalAlign: "middle"}}>{"Difficulty: " + diff}</span>
</div>
<div className="modal--infotext">
<span>*Values given by estimated calories were from a moderately intense workout for a healthy individual.</span>
</div>
</div>
</div>
);
}
export default Modal;
I suspect it is because when you click the button it executes document.querySelector('.modal').classList.toggle('modal--hidden'); which toggles the modal--hidden class on all modals, so no matter which button you click both modals are opened and you only see the one that is on top.
You probably want to add an open prop to your Modal component and use that prop to conditionally add the modal--hidden class to the root modal div.
Does vue.js have an equivalent of Angular's *ngTemplateOutlet directive? Let's say I have some components defined like this:
<template>
<div id="independentComponent">
Hello, {{firstName}}!
</div>
</template>
<script>
export default {
name: "independentComponent",
props: ['firstName']
}
</script>
...
<template>
<div id="someChildComponent">
<slot></slot>
<span>Let's get started.</span>
</div>
</template>
<script>
export default {
name: "someChildComponent"
}
</script>
I want to be able to do something like this:
<template>
<div id="parentComponent">
<template #indepdentInstance>
<independentComponent :firstName="firstName" />
</template>
<someChildComponent>
<template #indepdentInstance></template>
</someChildComponent>
</div>
</template>
<script>
export default {
name: "parentComponent",
components: {
someChildComponent,
independentComponent
},
data() {
return {
firstName: "Bob"
}
}
}
</script>
In Angular, I could accomplish this with
<div id="parentComponent">
<someChildComponent>
<ng-container *ngTemplateOutlet="independentInstance"></ng-container>
</someChildComponent>
<ng-template #independentInstance>
<independentComponent [firstName]="firstName"></independentComponent>
</ng-template>
</div>
But it looks like Vue requires the element to be written to the DOM exactly where it is in the template. Is there any way to reference an element inline and use that to pass to another component as a slot?
You cannot reuse templates like ngTemplateOutlet, but can combine idea of $refs, v-pre and runtime template compiling with v-runtime-template to achieve this.
First, create reusable template (<ng-template #independentInstance>):
<div ref="independentInstance" v-show="false">
<template v-pre> <!-- v-pre disable compiling content of template -->
<div> <!-- We need this div, because only one root element allowed in templates -->
<h2>Reusable template</h2>
<input type="text" v-model="testContext.readWriteVar">
<input type="text" v-model="readOnlyVar">
<progress-bar></progress-bar>
</div>
</template>
</div>
Now, you can reuse independentInstance template:
<v-runtime-template
:template="$refs.independentInstance.innerHTML"
v-if="$refs.independentInstance">
</v-runtime-template>
But keep in mind that you cannot modify readOnlyVar from inside independentInstancetemplate - vue will warn you with:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "readOnlyVar"
But you can wrap it in object and it will work:
#Component({
components: {
VRuntimeTemplate
}
})
export default class ObjectList extends Vue {
reusableContext = {
readWriteVar: '...'
};
readOnlyVar = '...';
}
You could try Portal vue written by LinusBorg a core Vue team member.
PortalVue is a set of two components that allow you to render a
component's template (or a part of it) anywhere in the document - even
outside the part controlled by your Vue App!
Sample code:
<template>
<div id="parentComponent">
<portal to="independentInstance">
<!-- This slot content will be rendered wherever the <portal-target>
with name 'independentInstance' is located. -->
<independent-component :first-name="firstName" />
</portal>
<some-child-component>
<portal-target name="independentInstance">
<!--
This component can be located anywhere in your App.
The slot content of the above portal component will be rendered here.
-->
</portal-target>
</some-child-component>
</div>
</template>
There is also a vue-simple-portal written by the same author that is smaller but that mounts the component to end of body element.
My answer from #NekitoSP gave me an idea for a solution. I have implemented the sample below. It worked for me. Perhaps you want to use it as a custom component with props.
keywords: #named #template #vue
<template>
<div class="container">
<div ref="templateRef" v-if="false">write here your template content and add v-if for hide in current place</div>
....some other contents goes here
<p v-html="getTemplate('templateRef')"></p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
Vue.extend({
methods:{
getTemplate(tempRef){
return this.$refs[tempRef].innerHTML
}
}
})
</script>
X-Templates
Use an x-template. Define a script tag inside the index.html file.
The x-template then can be referenced in multiple components within the template definition as #my-template.
Run the snippet for an example.
See the Vue.js doc more information about x-templates.
Vue.component('my-firstname', {
template: '#my-template',
data() {
return {
label: 'First name'
}
}
});
Vue.component('my-lastname', {
template: '#my-template',
data() {
return {
label: 'Last name'
}
}
});
new Vue({
el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-firstname></my-firstname>
<my-lastname></my-lastname>
</div>
<script type="text/x-template" id="my-template">
<div>
<label>{{ label }}</label>
<input />
</div>
</script>
Not really sure i understand your problem here, but i'll try to give you something that i will opt to do if i want to add two components in one template.
HeaderSection.vue
<template>
<div id="header_id" :style="'background:'+my_color">
welcome to my blog
</div>
</template>
<script>
export default {
props: ['my_color']
}
</script>
BodySection.vue
<template>
<div id="body_id">
body section here
</div>
</template>
<script>
export default {
}
</script>
home.vue
<template>
<div id="parentComponent">
<header-section :color="my_color" />
<body-section />
</div>
</template>
<script>
import HeaderSection from "./components/HeaderSection.vue"
import BodySection from "./components/BodySection.vue"
export default {
name: "home",
components: {
HeaderSection,
BodySection
},
data() {
return {
my_color: "red"
}
}
}
</script>