I'm trying to import Quill Editor into a Nuxt3 project and want to use it in a componenent.
This is what I am trying to do:
QuillEditorWrapper.client.vue
<script>
import '../node_modules/#vueup/vue-quill/dist/vue-quill.snow.css';
export default {
name: 'NotQuillEditor',
setup() {
if (process.client) {
const { QuillEditor } = import('#vueup/vue-quill');
return { QuillEditor };
}
},
};
</script>
<template>
<h1>Quill Editor</h1>
<QuillEditor theme="snow" toolbar="full" /> <!-- same for <quill-editor> -->
</template>
This mounts the component but does not launch quill editor. The following vue warning is displayed:
[Vue warn]: Failed to resolve component: QuillEditor
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
A full reproduction is available here: https://stackblitz.com/edit/github-qsdpjt-me572c?file=components/QuillEditorWrapper.client.vue
Related
I have created npm library that is installed on another project through package.json. The library is created in Vue3. The problem is that components that are created with script setup are not recognized by IDE (WebStorm) and components that are created with Options API (without script setup) are recognized. Both components works, but the problem is that for example test-input component is not recognized and test-button components is.
vite.config.ts
build: {
cssCodeSplit: false,
lib: {
entry: './src/TestDesignSystemPlugin.ts',
formats: ['es', 'cjs'],
name: 'TestDesignSystemPlugin',
fileName: (format) => (format === 'es' ? 'index.js' : 'index.cjs'),
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue',
},
},
},
},
TestButton.vue - Component created with Options API
<template>
<button>
<slot />
</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'TestButton',
})
</script>
TestInput.vue - Component created with Composition API
<template>
<input v-model="model" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const model = ref('')
</script>
Also this is TestDesignSystemPlugin.ts file that is used in vite.config.ts and where components are installed:
import type { App } from 'vue'
import {
TestButton,
TestInput,
} from '#/components'
export default {
install: (app: App) => {
app.component('TestButton', TestButton)
app.component('TestInput', TestInput)
},
}
UPDATE:
I don't think that issue is with IDE, than with the build of the library (plugin). When I see index.js of the build I see the difference between components that are with setup and without setup:
var TestDesignSystemPlugin = {
install: (app) => {
app.component("TestButton", TestButton);
app.component("TestButtonSocial", TestButtonSocial);
app.component("TestInput", _sfc_main$8);
}
};
I’ve built my first project and have run the build process. I have my index.html file and it works if opened directly.
I’ve copied the code into an existing html page and the initial page load is fine. However, when props get updated, binding (v-if statements) no longer works.
Any help would be great
Edit with code example
<script>
import { ref } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
export default {
components: {
'Determining': Determining,
'Ready': Ready,
},
setup() {
let checkout = ref({
state: 'determining',
});
return {
checkout,
};
},
created() {
this.checkout.state = 'ready';
console.log("I am getting here");
}
}
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>
The determining state is shown when the page first loads. The console log is firing in setup, but Ready component is not showing
Progress
I've narrowed it down to other javascript running on the page.
Any javascript, even just
<script>console.log("hello");</script>
Is enough to break it.
Other than adding additional javascript to Vue, is there anyway around it?
if I'm not wrong, you can't access composition api or setup() variables in options api (such as created, mounted, data, methods etc). You can use beforeMount as #Thomas commented or onMounted by importing it from vue, for the example:
<script>
import { ref, beforeCreate } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
export default {
components: {
'Determining': Determining,
'Ready': Ready,
},
setup() {
beforeCreate(()=> {
checkout.state.value = 'ready';
console.log("I am getting here");
})
let checkout = ref({
state: 'determining',
});
return {
checkout,
};
}
}
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>
if you want it more simple, you can use script sugar setup, this way you don't need to return in stup(). It can make your code simpler but if you want to define props, the approach is different
<script setup>
import { ref, beforeCreate } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
beforeCreate(()=> {
checkout.state.value = 'ready';
console.log("I am getting here");
})
let checkout = ref({
state: 'determining',
});
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>
I'm trying to use CodeMirror on Vue3 and the problem occurs when I call doc.setValue().
The Problem is following:
Cursor position is broken when doc.setValue() is called
CodeMirror throws an exception when continuing editing
The exception is here.
Uncaught TypeError: Cannot read property 'height' of undefined
at lineLength (codemirror.js:1653)
at codemirror.js:5459
at LeafChunk.iterN (codemirror.js:5623)
at Doc.iterN (codemirror.js:5725)
at Doc.iter (codemirror.js:6111)
at makeChangeSingleDocInEditor (codemirror.js:5458)
at makeChangeSingleDoc (codemirror.js:5428)
at makeChangeInner (codemirror.js:5297)
at makeChange (codemirror.js:5288)
at replaceRange (codemirror.js:5502)
How should I solve this?
~~~
Versions are CodeMirror: 5.61.1, Vue.js: 3.0.11
My code is following:
index.html
<div id="app"></div>
<script src="./index.js"></script>
index.js
import { createApp } from 'vue';
import App from './App';
const app = createApp(App);
app.mount('#app');
App.vue
<template>
<div>
<button #click="click">Push Me</button>
<textarea id="codemirror"></textarea>
</div>
</template>
<script>
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
this.cm.getDoc().setValue('foo\nbar');
}
}
}
</script>
Thanks.
UPDATES
First, this problem also occurs when I used replaceRange() with multiline.
Unfortunately, I couldn't find any solution. So I tried to find another way.
My solution is recreating Codemirror instance with a textarea that has new content.
It works well.
// Remove old editor
this.cm.toTextArea();
// Get textarea
const textarea = document.getElementById('codemirror');
// Set new content
textarea.value = 'foo\nbar';
// Create new editor
this.cm = CodeMirror.fromTextArea(textarea, { /** options */ });
I found a method, you can use toRaw to get the original Object from Proxy,and this method can be also used in monaco-editor
import { toRaw } from 'vue'
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
toRaw(this.cm).setValue('foo\nbar');
}
}
}
Another way,you don't have to define cm in data, just use this.cm
data () {
return {
//cm: null
}
},
I want to use third party library element-plus in my component. In setup defineComponent entends that component. In console, it would warn Failed to resolve component: el-radio at <App>
In about router, Here is the about.vue
<template>
<div id="popup-content"></div>
</template>
<script>
import {
onMounted, createApp, defineComponent, nextTick,
} from 'vue';
import Test from '#/components/Test.vue';
export default {
setup() {
onMounted(() => {
const myNewComponent = defineComponent({
extends: Test,
});
createApp(myNewComponent).mount('#popup-content');
nextTick(() => {
createApp(myNewComponent).mount('#popup-content');
});
});
},
}
Test component has used element-plus el-raido component, Test.vue
<template>
<el-radio v-model="radio" label="1">备选项</el-radio>
<el-radio v-model="radio" label="2">备选项</el-radio>
</template>
<script>
export default {
data() {
return {
radio: '1',
};
},
};
</script>
I have add element-plus, and register all in main.js
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
import App from './App.vue';
const app = createApp(App);
app.use(ElementPlus);
app.mount('#app');
I have found this question
Extend vue.js component from third-party library
I really really don't understand what are you trying to achieve by extending your perfectly fine Test component BUT...
Vue 3 is very different from Vue 2 - a lot of global API's (as component registration for example) are not global anymore but are tight to a "app instance" (created by createApp)
So even if you register Element components in main.js (app.use(ElementPlus);), the another app instance (why!?) created in onMounted hook of about.vue component knows nothing about the components! That is the reason for an error...
You must register components in every app instance created by createApp you want to use them in ....
As #Michal Levý answered, I need to register components in every app instance created by createApp.
Here is the working version about.vue, in case someone need.
<template>
<div id="popup-content"></div>
</template>
<script>
import {
onMounted, createApp, defineComponent, nextTick,
} from 'vue';
import Test from '#/components/Test.vue';
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
export default {
setup() {
onMounted(() => {
const myNewComponent = defineComponent({
extends: Test,
});
const app1 = createApp(myNewComponent);
nextTick(() => {
app1.use(ElementPlus);
app1.mount('#popup-content');
});
});
},
}
im using video.js in react for building video player but when im installing it using npm pacakage its does not provide its inbuilt css how i can add inbuilt css of video.js, instead of control bar im getting something like shown in picture below
import React, { Component } from 'react';
import videojs from 'video.js';
import { sendData } from '../../analytics/sendData';
class Video360Player extends Component {
componentDidMount() {
// instantiate Video.js
const videoJsOptions = {
autoplay: true,
controls: true,
sources: [{
src: this.props.videoUrl,
type: 'video/mp4'
}]
}
this.player = videojs(this.videoNode, videoJsOptions,this.props, function onPlayerReady() {
console.log('onPlayerReady', this)
});
}
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose()
}
}
// wrap the player in a div with a `data-vjs-player` attribute
// so videojs won't create additional wrapper in the DOM
// see https://github.com/videojs/video.js/pull/3856
render() {
return (
<div>
<div data-vjs-player>
<video ref={ node => this.videoNode = node } className="video-js"></video>
</div>
</div>
)
}}
export default Video360Player
Add the following line on top of component file:
import 'video.js/dist/video-js.css';
As pointed here: https://docs.videojs.com/tutorial-react.html
The reason your video is not playing is because the player is not ready. I ran into the same problem and the solution is explained in the documentation.
Basically, You must have a function to change the video source only when the player is ready.
const changePlayerOptions = () => {
// you can update the player through the Video.js player instance
if (!playerRef.current) {
return;
}
// [update player through instance's api]
playerRef.current.src([{ src: 'https://vjs.zencdn.net/v/oceans.mp4', type: 'video/mp4' }]);
};
It is explained in details here https://docs.videojs.com/tutorial-react.html