Creating a simple VUE.JS application - vue.js

I am trying to use a simple polygon cropper from Vue within an application by following the steps in this article.
I created my app using:
vue init webpack myproject
Now, I need to add the sample template to my app (it has a src folder), but I am not sure how to amend or add this piece of code to my application. The template should be as follows per the linked article:
// Global
import Vue from 'vue';
import VuePolygonCropper from 'vue-polygon-cropper';
Vue.component(VuePolygonCropper);
// Local
import VueCropper from 'vue-polygon-cropper';
export default {
components: { VueCropper}
}
<template>
<div id="app">
<polygon-crop :imageSource="'/demo.png'" ref="canvas"></polygon-crop>
<button #click.prevent="crop">Crop</button>
<button #click.prevent="undo">Undo</button>
<button #click.prevent="redo">Redo</button>
<button #click.prevent="reset">Reset</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
crop: function () {
this.$refs.canvas.crop();
},
undo: function () {
this.$refs.canvas.undo();
},
redo: function () {
this.$refs.canvas.redo();
},
reset: function () {
this.$refs.canvas.reset();
}
}
};
</script>
I am not sure what the meaning of global or local is there. My src folder structure is as follows:
Directory of C:\ThermoAnalyser\vue_js\myproject\src
27/12/2020 11:37 AM <DIR> .
27/12/2020 11:37 AM <DIR> ..
27/12/2020 11:37 AM 374 App.vue
27/12/2020 11:37 AM <DIR> assets
27/12/2020 11:37 AM <DIR> components
27/12/2020 11:37 AM 360 main.js
27/12/2020 11:37 AM <DIR> router
2 File(s) 734 bytes
5 Dir(s) 301,183,393,792 bytes free

You won't be able to get this component running with just this code snippet, there's a couple of things that you would need to do to fix this up.
Before we go any deeper, I would like you to make sure if you have installed this vue-polygon-cropper component. If you navigated to the package.json that is located in the same level as your "src" folder, you would see a mention of vue-polygon-cropper there, if not please install it by npm install vue-polygon-croper .
Let's take a look at your <template> section first:
1- In the template, you call a component <polygon-crop> but, there is no component registered by that name in your script (What you are attempting to register is 'VuePolygonCropper' so you should try using <VuePolygonCropper> component instead.
2-I see there you copied and pasted the logo image in assets, that's a great way to test it! However, Digging through the creator's example that they put up on github, It seems like this component requires a full path to your image file instead of the relative path. so instead of /src/assets/logo.png try doing :imageSource="require('../assets/logo.png')"
I'm assuming the assets logo is on a folder that is one level above your current component.
So your template should look like this:
<template>
<div id="app">
<VuePolygonCropper :imageSource = "require('../assets/logo.png')"
ref="canvas"> </VuePolygonCropper>
<button #click.prevent="crop"> Crop </button>
<button #click.prevent="undo"> Undo </button>
<button #click.prevent="redo"> Redo </button>
<button #click.prevent="reset"> Reset </button>
</div>
</template>
Now on to your script!
just import the VuePolygonCropper and mention it as a component in the components section.
You don't need to import vue and do Vue.component(VuePolygonCropper). The correct way to register this component would be like this
<script>
import VuePolygonCropper from 'vue-polygon-cropper';
export
default
{
name: 'App',
components:{VuePolygonCropper},
methods: {
crop: function() {
this.$refs.canvas.crop();
},
undo: function()
{
this.$refs.canvas.undo();
},
redo: function()
{
this.$refs.canvas.redo();
},
reset: function()
{
this.$refs.canvas.reset();
}
}
};
</script>
For the heck of it, I have created a codesandbox that you can play around with . You can try to play around with the App.vue file and see how it was created.
Happy coding!

"Global" vs "Local"
The "global" and "local" comments refer to global component registration and local component registration. The article shows both ways of registering the vue-polygon-cropper component probably to make it easier to copy-paste into your own code.
Global component registration
You can register a component globally so that it could be used in another component without the consuming component having to register it locally. This is normally used for commonly used components that are frequently found in several components (e.g., a button).
Below is an example of global component registration that allows MyButton to be used in MyForm. Notice how MyForm's <template> uses MyButton without any component registration for MyButton in its <script>.
// main.js
import Vue from 'vue'
Vue.component('MyButton', { /*...*/ })
// MyForm.vue
<template>
<MyButton #click="onClick" />
</template>
<script>
export default {
methods: {
onClick() { /*...*/ }
}
}
</script>
Local component registration
For seldom used components (ones that are only found in a few components of your app), register the components locally instead to help minimize the bundle size if needed. If your component is never used (e.g., from a refactoring down the road), local registration allows the bundler to crop out your component from the final output.
Here's the previous example with local registration instead:
// MyButton.vue
<template>
<button />
</template>
// MyForm.vue
<template>
<MyButton #click="onClick" />
</template>
<script>
import MyButton from './MyButton.vue'
export default {
components: {
MyButton 👈
},
methods: {
onClick() { /*...*/ }
}
}
</script>
Getting started with the sample code
To quickly get the sample code working in your project:
Copy the <template> and <script> parts of the sample code into your src/App.vue, replacing everything.
In the App.vue's component definition, locally register vue-polygon-cropper as polygon-crop:
<script>
import VuePolygonCropper from 'vue-polygon-cropper'
export default {
components: {
'polygon-crop': VuePolygonCropper
}
}
<script>
The sample code refers to an image at /demo.png, but your sample app only has src/assets/logo.png, so edit src/App.vue's <template> so that polygon-crop uses src/assets/logo.png. We have to require the asset's path so that Webpack properly resolves the path from source:
<polygon-crop :imageSource="require('#/assets/logo.png')">
sample GitHub repo
Update to Vue CLI
Consider using Vue CLI's default generated templates (from vue create) instead of that outdated webpack template. The newly created project would still use Webpack, but most of the config for developer ergonomics are abstracted away, which can be helpful for beginners.
vue create myproject

Related

Creating a vue.js component [duplicate]

This question already has answers here:
Creating a simple VUE.JS application
(2 answers)
Closed 2 years ago.
I have created a vue.js application by
vue init webpack myproject
I am then following a link, to create simple copper component, I have put that under src/components directory as follow:
<template>
<div id="app">
<polygon-crop :imageSource = "'src/assets/logo.png'"
ref="canvas"> </polygon-crop>
<button #click.prevent="crop"> Crop </button>
<button #click.prevent="undo"> Undo </button>
<button #click.prevent="redo"> Redo </button>
<button #click.prevent="reset"> Reset </button>
</div>
</template>
<script>
import Vue from 'vue';
import VuePolygonCropper from 'vue-polygon-cropper';
Vue.component(VuePolygonCropper);
export
default
{
name: 'App',
methods: {
crop: function() {
this.$refs.canvas.crop();
},
undo: function()
{
this.$refs.canvas.undo();
},
redo: function()
{
this.$refs.canvas.redo();
},
reset: function()
{
this.$refs.canvas.reset();
}
}
};
</script>
But actually, it doesn't render properly and my component doesn't show up properly. I am new to vue.js and any help would be appreciated!
You won't be able to get this component running with just this code snippet, there's a couple of things that you would need to do to fix this up.
Before we go any deeper, I would like you to make sure if you have installed this vue-polygon-cropper component. If you navigated to the package.json that is located in the same level as your "src" folder, you would see a mention of vue-polygon-cropper there, if not please install it by npm install vue-polygon-croper .
Let's take a look at your <template> section first:
1- In the template, you call a component <polygon-crop> but, there is no component registered by that name in your script (What you are attempting to register is 'VuePolygonCropper' so you should try using <VuePolygonCropper> component instead.
2-I see there you copied and pasted the logo image in assets, that's a great way to test it! However, Digging through the creator's example that they put up on github, It seems like this component requires a full path to your image file instead of the relative path. so instead of /src/assets/logo.png try doing :imageSource="require('../assets/logo.png')"
I'm assuming the assets logo is on a folder that is one level above your current component.
So your template should look like this:
<template>
<div id="app">
<VuePolygonCropper :imageSource = "require('../assets/logo.png')"
ref="canvas"> </VuePolygonCropper>
<button #click.prevent="crop"> Crop </button>
<button #click.prevent="undo"> Undo </button>
<button #click.prevent="redo"> Redo </button>
<button #click.prevent="reset"> Reset </button>
</div>
</template>
Now on to your script!
just import the VuePolygonCropper and mention it as a component in the components section.
You don't need to import vue and do Vue.component(VuePolygonCropper). The correct way to register this component would be like this
<script>
import VuePolygonCropper from 'vue-polygon-cropper';
export
default
{
name: 'App',
components:{VuePolygonCropper},
methods: {
crop: function() {
this.$refs.canvas.crop();
},
undo: function()
{
this.$refs.canvas.undo();
},
redo: function()
{
this.$refs.canvas.redo();
},
reset: function()
{
this.$refs.canvas.reset();
}
}
};
</script>
For the heck of it, I have created a codesandbox that you can play around with . You can try to play around with the App.vue file and see how it was created.
Happy coding!

What is the purpose of Vue.use() while importing a plugin? If we have already used vue.use , is it required to add it to the components

I'm using the plugin vue-flag-icon - https://www.npmjs.com/package/vue-flag-icon for flags, In their documentation I saw the following steps for initialising.
import FlagIcon from 'vue-flag-icon'
Vue.use(FlagIcon);
Do I need to have this? This is not specified in their docs!
export default {
components: {
FlagIcon. /// do i need to give it here ?
},
}
What is the purpose of this Vue.use(...), It's working fine even if I remove that. Can somebody help me out?
Checked the vue documentation - https://v2.vuejs.org/v2/guide/plugins.html.
Did not get a clear idea about it
Vue.use automatically prevents you from using the same plugin more than once, so calling it multiple times on the same plugin will install the plugin only once.
For the flag component, it declares a global component that you can refer within your components, such that in the following example will render correctly.
in vue-flag-icon source code
install: function (Vue) {
if (VuePlugin.installed) {
return;
}
VuePlugin.installed = true;
Vue.component('flag', Flag);
}
You can see that with Vue.component('flag', Flag) that this is a root level component declaration, therefore, in your components, you do not require to declare something like following
Unnecessary if using Vue.use
import { Flag } from "vue-flag-icon"
export default {
components: { Flag }
}
If Vue.use is not used, the flag tag in the template will throw an error if you do not include it as a component within your vue init.
<template>
<div id="app">
<img src="./assets/logo.png">
<flag iso="it" />
<flag iso="gb" />
<flag iso="us" />
</div>
</template>
<script>
export default {
name: 'app',
}
</script>

Vue js loading js file in mounted() hook

I have the following Vue component:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
mounted(){
// this is syntax error
import './assets/js/otherjsfile.js'
}
}
</script>
As is clear from the code snippet, I want to have the otherjsfile.js loaded in mounted() hook. That script file has certain IIFEs which expects the html of the web page to be fully loaded.
So how do I invoke that js file in a lifecycle hook?
This is the pattern I use. The example is importing a js file which contains an IIFY, which instantiates an object on window.
The only problem with this would occur if you want to use SSR, in which case you need Vue's <ClientOnly> component, see Browser API Access Restrictions
mounted() {
import('../public/myLibrary.js').then(m => {
// use my library here or call a method that uses it
});
},
Note it also works with npm installed libraries, with the same path conventions i.e non-relative path indicates the library is under node_modules.
I'm a little unsure of what your asking. But if you are just trying to include an external js file in your page, you can just use the script tag in your template and not have to put anything in your mounted function, like this:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
<script src="./assets/js/otherjsfile.js"></script>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
}
</script>
Does this solve your issue?

Nested single file components - vue.js with electron-forge

I am trying electron for the first time and I am blown away by it. I have hit a wall, though, when trying to use single file vue.js components using electron-forge. My problem is the following:
I create a project using the vue.js template and run it. Works and looks great. I have a single file page with an index file that looks like this:
<div id="test"></div>
</body>
<script>
import Vue from 'vue';
import Test from './test';
const app = new Vue(Test).$mount('#test');
app.text = "Electron Forge with Vue.js!";
</script>
So far, so good. It imports Test, which is a single file component and renders it.
Now, I would like to have other single file components nested in this main component. For example, I would like to have the following, in my app file called test.vue
<template>
<h2>Hello from {{text}}</h2>
</template>
<script>
import About from './About.vue'
export default {
components: {
appAbout: About,
},
data () {
return {
text: 'Electron'
}
}
}
</script>
Again, so far so good. I can run the app with no errors so the component is being imported.
Here comes my problem: if I now try to render the component using <appAbout></appAbout>, as I have done before in web apps with vue.js, I get the following error.
It basically says that I am not using a single root element in my component, which is really strange because my component looks like this:
<template lang="html">
<div>Hello from component</div>
</template>
<script>
export default {
}
</script>
<style lang="css">
</style>
I am stuck. Can someone please help?
So I have tried a few different things with no success, like using or even as the component names.
I also have tried these two ways of starting the vue:
The way you get with electron-forge
const app = new Vue(App).$mount('#app')
and the way I learned
new Vue({el: '#app', render: h => h(App)})
Nothing seems to work...
Define your component like this :
export default {
components: {
'app-about': About
}
}
Then use it in template like this (with kebab-case) :
<app-about></app-about>
About your compiling template error you need to wrap everything in test.vue in a root element :
<template>
<div>
<h2>Hello from {{text}}</h2>
<app-about></app-about>
</div>
</template>

How to use Onsen UI tabbar with Vue single file components

I'm using Vue Onsen UI and trying to render a Vue single file component for each tab.
In the documentation here, they make use of template in a single page. Which is not very reusable. I want to be able to import custom component and render that.
Here is something that I'm trying to do which doesn't seem to work.
<template lang="html">
<v-ons-page>
<!-- top tab bar -->
<v-ons-tabbar position="top" :index="0">
<v-ons-tab label="Browse" page="TaskList">
</v-ons-tab>
<v-ons-tab label="Second">
</v-ons-tab>
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
export default {
template: '#main',
components: {
'task-list': TaskList,
},
};
</script>
<style lang="scss">
</style>
Can you suggest anything that I should try?
Instead of using tab objects that reference the components directly, use the :tabs property of the tabbar to set up the pages:
<template lang="html">
<v-ons-page>
<v-ons-tabbar position="top" :index="0" :tabs="tabs">
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
import SecondPage from './SecondPage';
export default {
template: '#main',
data: function () {
return {
tabs: [
{label: 'Browse', page: TaskList},
{label: 'Second', page: SecondPage}
]
}
}
};
</script>
Also, make sure the root element of the components you reference in the page property are <v-ons-page> elements.
I was having the same difficulty with the following syptoms:
Tabs were not appearing at all
No errors in CLI or in console
Note that I was also using the "Hello World" app that is generated from the CLI (vue init OnsenUI/vue-pwa-webpack hello-world)
Resolution
It was pretty simple in the end: there is a file in the root of the folder called vue-onsen-components.js which has all of the components and some of them are commented out. I had to uncomment the following lines and then the tabs appeared:
export { default as VOnsTab } from 'vue-onsenui/esm/components/VOnsTab'
export { default as VOnsTabbar } from 'vue-onsenui/esm/components/VOnsTabbar'