I've just started learning Vue. Now I'm trying to build my first component, but the template didn't show up, and the console didn't give me any error.
Here's some of my code:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
and here's a Jsbin with my full code
Your Vue instance needs a mounting id specified in the el property:
var vm = new Vue({
el: '#app', // Specifying a DOM id "app"
data() {
// ...
}
})
And the app template needs to be wrapped with that same id:
<div id="app">
<button-counter></button-counter>
</div>
Demo:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
var vm = new Vue({
el: '#app',
data() {
return {
name:'yazid',
age:'20',
date:'press to known the date',
skills:['HTML','CSS','JS'],
ele:'<h1> elements from vue js</h1>',
completed_languages:[{
lang:'html',
percent:'90%'
},{
lang:'CSS',
percent:'70%'
},{
lang:'JS',
percent:'70%'
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button-counter></button-counter>
</div>
Related
const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
components: {
CustomComponent
},
props: ['templateString'],
template: `<section v-html="templateString"></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result :template-string="generateTemplate()">
</div>
I want to render a custom component which has a dynamical template base on user input.
when user input a specific string ([:component-1]), it will be render as a component (CustomComponent)
how to achieve this?
Thanks a lot for anyone help!
You should look into v-slot
https://v2.vuejs.org/v2/guide/components-slots.html
Example:
Parent:
<child-component v-html="myTemplate">
<span>From parent</span>
</child-component>
Child:
<div>
<v-slot></v-slot> //Will output "<span>From parent</span>"
</div>
**Added more explaination
You can then condition check and update myTemplate to your desired template. "<span>From parent</span>" is just there for explanation on how slot works.
updated by the questioner
const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
template: `<section><slot></slot></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult,
CustomComponent
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result>
{{ generateTemplate() }}
</user-input-result>
</div>
I figured it out by using Vue.complie
according to dynamically-fetch-and-compile-a-template-with-nuxt
const UserInputResult = {
props: ['templateString'],
render(h){
return h({
components: {
CustomComponent
},
template: `<section>${this.templateString}</section>`
});
}
}
In the following example, I would like a component that doubles a number. This number is passed not as a property, but as content. How is it possible to get the content value in Vue?
var twice = {
template: '<div>{{ value }}</div>',
computed: {
value() {
return parseInt(this.$slot) * 2;
}
}
};
new Vue({
el: '#app',
components: {
twice: twice
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="app">
<twice>21</twice>
</div>
You could access the default slot text by this.$slots.default[0].text :
var twice = {
template: `<div>
number : <slot></slot><br>
<div>double : {{ value }}</div>
</div>`,
computed: {
value() {
return parseInt(this.$slots.default[0].text) * 2;
}
},
mounted() {
console.log(this.$slots.default[0].text)
}
};
new Vue({
el: '#app',
components: {
twice: twice
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<twice>21</twice>
</div>
I'm just learning Vue, and now starting with props. I'm having trouble integrating them into my code below.
I want to make so a prop name can be sent to the greet component. I want name to be shown in the component<greet name="User"></greet> and it to render: <div>Welcome, User!</div>
Vue.component('greet', {
data() {
return {
}
},
template: '<div>Welcome !</div>'
})
new Vue({ el: '#app' })
There is good documentation about it
Vue.component('greet', {
props: {
'player-name': {
type: String,
required: true
}
},
data() {
return {
}
},
template: '<div>Welcome {{playerName}}!</div>'
})
new Vue({
el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<greet player-name="User"></greet>
</div>
I know use $emit to pass data from child to parent components on VueJS but I want get that value on javascript function. My scenario is:
Parent
created () {
this.$on('getValue', function (params) {
console.log('PARAMS: ' + params)
})
},
Child
methods: {
checkBoxChanged (index) {
this.$emit('getValue', 'some value')
},
}
But it ins't works. Using html I can set on Parent using something like: (I'VE REASONS TO CAN'T DO IT!)
<template>
<div>
<h1>{{ message }}</h1>
<child v-on:listenerChild="listenerChild"/>
</div>
</template>
But I need do this using just javascript.
That's how you can pass data from child to parent:
Vue.component('child-component', {
template:
`<button type="button" #click="emitClick">
Click to emit event to parent component
</button>`,
methods: {
emitClick() {
this.$emit('buttonClicked', 'Magic from child component!');
},
},
});
Vue.component('parent-component', {
template:
`<div>
<div>Child data is: {{ childData }}</div>
<child-component #buttonClicked="handleClick" />
</div>`,
data() {
return {
childData: 'empty',
};
},
methods: {
handleClick(data) {
this.childData = data;
},
},
});
new Vue({
el: '#app',
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<parent-component />
</div>
I've created a simple component:
https://jsfiddle.net/s08yhcda/1/
<div id="app">
<button-counter>My counter: <span v-text="count"></span></button-counter>
</div>
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
el: '#app'
})
Yet I cannot bind to the inner component data (counter). How can a component expose its data to the <slot> scope? I know the "events up, props down" idea. But still I thought it would be possible to bind component data inside its scope (inside the <button-counter> element)
I prefer not using event for something that simple. Any other way?
There are multiple ways to solve this problem:
Using events
This is usually the best method, as it is expected by other Vue developer
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
this.$emit('input', this.count);
},
},
template: '<button v-on:click="click"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
data() {
return {
count: 0,
};
},
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter #input="count = $event">My counter: <span v-text="count"></span></button-counter>
</div>
Using refs:
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
},
},
template: '<button v-on:click="click"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
data() {
return {
mounted: false,
};
},
mounted() {
this.mounted = true;
},
computed: {
count() {
return this.mounted ? this.$refs.counter.count : 0;
},
},
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter ref="counter">My counter: <span v-text="count"></span></button-counter>
</div>
Using slot-scope
Using slot scope, you can pass multiple arguments to the parent slot:
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
},
},
template: '<button v-on:click="click"><slot :count="count"></slot></button>'
})
// boot up the demo
var demo = new Vue({
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter>
<span slot-scope="prop">
My counter:
<span v-text="prop.count"></span>
</span>
</button-counter>
</div>
You can send data to the slot. Look at this example:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++"><slot :count="count" /></button>'
})
<div id="app">
<button-counter>
<template scope="props">
My counter: <span>{{ props.count }}</span>
</template>
</button-counter>
</div>
https://jsfiddle.net/s08yhcda/2/