Keep existing markup in Vue's <div id="app" /> - javascript

I have installed Vue using the latest CLI in to an existing .net mvc projects. My goal is to add components while keeping the existing pages intact.
Is it possible to do something like:
<div id="app">
<MyNewVueComponent></MyNewVueComponent> <!-- insert my vue compoents -->
<p>#Model.someText</p> <!-- keep original .net mvc view content -->
</div>
In my main.js:
new Vue({}).$mount('#app')
This just generates a blank page at the moment.

Using
new Vue({
el: '#app'
})
along with runtimeCompiler: true in vue.config.js did the trick.

Related

Is there a way to suppress VueJS "Cannot find element" warning

I have a script file that contains two Vue apps, that I use across multiple django templates. Apps are vue1, and vue2, with el: #vue1-app, and el: #vue2-app.
On one particular page I only use one of those apps, not both. So my html contains only <div id="vue1-app"></div> and not both divs with vue1-app and vue2-app ids. Therefore Vue logs warnings "Cannot find element: #vue2-app".
Is there a way to suppress those warning or any other bypass?
Thank you!
I'm not a Django developer, but I think maybe you can just split out them into two files or add a condition like:
const vueApp = document.querySelector('#vue-app')
if(vueApp){
// mount the app
}
Vue warnings are not emitted in the production (minified) version of Vue, so you could load vue.min.js:
new Vue({
el: '#does_not_exist',
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.min.js"></script>
<div id="app">
<p>{{ message }}</p>
</div>

Vuejs and drupal

I'm working on a Drupal project where we compile the js and sass of the theme with webpack. As we are moving in a near future to other backend(Laravel), and the idea is to use vuejs on front-end. So it seems to us a good idea, in meanwhile, start using vuejs in some pages and components, so we could start learn it about it. I have experience with angular and react but none with vue. I add it vue, the vue-loader, etc, but seems dificult to make it work and I'm not sure which could be the best way to implement/add vuejs in this escenario. Any recomendation or link will we very helpful.
Introduction
Vue is good choice because of two reasons in your case:
It is simplest to learn than Angular and React
It is progressive - it means you can easy use it only in constrained part of your existing project.
If you look at dock of life cycle of Vue instance
https://v2.vuejs.org/v2/guide/instance.html
You will see there are some options of create template and connect it with instance of vue.
a) by "el" option - selecting existing element from dom
b) by template option
including template as a string
selecting template by id of script with type text/x-template
You can use Vue instantly after page load or mount it later so you have flexibility.
Examples
I understood your question is about simplest way to integrate vue with drupal. I think that these examples of use Vue on simple html page will help you.
Simplest way
Simplest way is use el option and load Vue from cdn. ( remember about change cdn to minified on production )
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app" v-cloak>
<h1>{{ heading }}</h1>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script>
new Vue({
el: "#app",
data: { heading: "Hello World" }
});
</script>
By using text/x-template
<div id="app"></div>
<script id="app-template" type="text/x-template">
<div>
<h1>{{heading}}</h1>
</div>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script>
let v = new Vue({
template: `#app-template`,
data: { heading: "Hello World" }
});
v.$mount();
document.querySelector("#app").appendChild(v.$el);
</script>

Which part of code would be rendered as virtual DOM?

I'm newbie in virtual DOM topic and last days I've been thinking of how it should work.
Let's imagine that I have a simple template engine in my project, for instance twig. And I'm using vue.js as a javascript framework.
So I could build the following page:
<div id="app">
<p>Some text</p>
<ul>
<li v-for="item in items">{{ item }}</li>
</ul>
<component><component/>
</div>
<template id="component">
<div class="center-xs">
<div class="row">
<div class="col-xs-12">
Some text
</div>
</div>
</div>
</template>
<script>
Vue.component('component', {
template: '#component'
});
var app = new Vue({
el: '#app',
data: {
items: ['item1', 'item2']
}
});
</script>
Which part of code would be Virtual DOM:
a. Nothing
b. Everything inside of #app
c. Items and component
d. Only component
And why? It'd great if share with me any info (links, your thoughts, official docs).
Thank u!
The code in the <div id=app> (e.g.<p> <ul>) is not DOM it is HTML markup that the browser then parses and then renders as its DOM. Since there is existing html code in the #app element it will be included by Vue as part of its template and thus be part of the Virtual DOM. Though technically since the <p> element never has any Vue operations performed on it, it is ignored.
If you have Vue Devtools extension installed in your browser you can see the representation of the Virtual DOM in the components view. <ROOT> will be your #app div of course, and then you will only see any <components> there, not the <p> element or even the <ul><li> elements.
It is a good practice to never have any html markup at all or otherwise component tags in your root element. Simply<div id='app'></div> then have all the other elements rendered exclusively by Vue through the Virtual DOM. This is achieved simply through the render function.
new Vue({
el: '#app',
components: {
TopLevelComponent
},
render: function(createElement) {
return createElement(TopLevelComponent);
}
})
https://v2.vuejs.org/v2/guide/render-function.html#The-Virtual-DOM

integrate a Vue.js page with WordPress?

I want to build a single page with Vue.js 2 and then add it to an existing WordPress website, e.g. as a new page in the menu. How will I do that inside WordPress? There is already an old WordPress site and I'm gonna develop a page/tool with Vue, so when it's finished I want to add it somewhere in the menu of the WordPress site as a new page.
Is it possible? What steps should I follow?
I created a custom template and inside I have a simple div message.
new Vue({
el: "#hello-world-app",
data() {
return {
msg: "Hello World!"
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="main-content" class="main-content">
<div id="primary" class="content-area">
<div id="content" class="site-content" role="main">
<div id="hello-world-app">
<h1>{{ msg }}</h1>
</div>
</div><!-- #content -->
</div><!-- #primary -->
</div><!-- #main-content -->
In functions.php I added these:
function my_enqueue_stuff() {
if ( get_page_template_slug() == 'page-surveypage.php' ) {
wp_enqueue_script('vue-dist', 'get_template_directory_uri() . '/js/vue.js, array (), 1.1, true );
wp_enqueue_script('vue-survey', 'get_template_directory_uri() . '/js/survey.js, array (), 1.1, true);
}
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_stuff' );
However, when I load the page with the custom template it shows
{{msg}}. Is it wrong that I downloaded the vue script and placed it in the js folder?
I would likely go with a new template in your (child-)theme. If this is just for this one page, then make it a specific page template, named with the slug of the page that will show your Vuejs app. If you'll want to use this on multiple pages, you could make a generic template file that authors can assign to any page they create, or you could wrap your vuejs component/app in a short code. (see the naming conventions of template files)
Once you've decided on a delivery method, then you'll just have to make sure to load the vuejs javascript file created by your bundler, as well as any dependencies that aren't bundled in your app.
Does that help?

Mixing Vue.js into existing SSR website?

Is it possible/viable to use Vue to create components that get instantiated onto custom tags rendered by e.g. a PHP application? Some kind of "custom elements light"?
It "works" if I mount the Vue instance onto the page root element, but - as far as I understand - Vue uses the whole page as a template in this case. And I imagine this could be a performance issue and cause trouble if other javascript code messes with the DOM.
The goal is to progressively replace legacy jQuery code. Is there an common approach for this problem?
Edit: Nesting these components is also a requirement. A simple example would be nested collapsibles.
Edit 2: Some fiddles to illustrate the problem.
A working solution based on riot.js:
https://jsfiddle.net/36xju9sh/
<div id="page">
<!-- This is supposed to show "This is a test." twice. -->
<test>
<test></test>
</test>
</div>
<script type="riot/tag">
<test>
<p>This is a test.</p>
<yield/>
</test>
</script>
<script>riot.mount('*')</script>
Two approaches using Vue.js:
https://jsfiddle.net/89ejjjsy/1/
HTML:
<div id="page">
<!-- This is supposed to show "This is a test." twice. -->
<test>
<test></test>
</test>
</div>
<script type="text/x-template" id="test-template">
<p>This is a test.</p>
<slot></slot>
</script>
Javascript:
Vue.config.ignoreCustomElements = ['test'];
// This won't hit the nested <test> element.
new Vue({
el:'test',
template: '#test-template',
});
// This does, but takes over the whole page.
Vue.component('test', {
template: '#test-template',
});
new Vue({
el: '#page',
});
You do not have to use whole page as Vue instance scope. It is more than ok to for example, use #comments-container as scope for comments component which will be nested somewhere on your page.
You can have multiple VueJS instances on one page.

Categories

Resources