{"id":28187,"date":"2022-11-14T08:44:53","date_gmt":"2022-11-14T08:44:53","guid":{"rendered":"http:\/\/implement-drag-and-drop-on-images-in-vue"},"modified":"2025-02-16T07:53:05","modified_gmt":"2025-02-16T15:53:05","slug":"implement-drag-and-drop-on-images-in-vue","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/","title":{"rendered":"Implement Drag and Drop on Images in Vue"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Many apps you\u2019ll encounter have images that you drag and drop in different locations for a number of reasons. It may help users reorganize their photo libraries or it can simplify a process. That\u2019s why we\u2019re going to build a front-end app to handle this type of drag and drop functionality.<\/p>\n<p>We\u2019re going to build a Vue app that lets us change the order of images using drag and drop and the images will come from your own Cloudinary account. By the time you finish, you\u2019ll have a Vue app that calls the Cloudinary API for images and lets you move them around.<\/p>\n<h2>Set up Vue project<\/h2>\n<p>Make sure you have Vue installed globally first. You can check that you have it installed with the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ vue --version\n\n@vue\/cli 5.0.8\n<\/code><\/span><\/pre>\n<p>If you don\u2019t have Vue installed, check out <a href=\"https:\/\/cli.vuejs.org\/guide\/installation.html\">the instructions here<\/a>. After this check, we can generate a new Vue project with this command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">$ vue create drag-<span class=\"hljs-keyword\">and<\/span>-drop\n\nVue CLI v5<span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.8<\/span>\n? Please pick a preset: <span class=\"hljs-keyword\">Default<\/span> (&#91;Vue <span class=\"hljs-number\">3<\/span>] babel, eslint)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Select the Vue 3 version because this is the most up-to-date version. Once the project has been set up, go to the <code>drag-and-drop<\/code> directory and briefly look through the files to get a sense of what we\u2019re starting with. Go to <code>src &gt; components &gt; HelloWorld.vue<\/code>. This is the file we\u2019re going to modify to implement the drag and drop functionality with the images we fetch from Cloudinary.<\/p>\n<p>If you don\u2019t already have a Cloudinary account, go set one up for free <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">here<\/a>. Upload a few images that you want to play with in this app. Then take note of your <code>cloud name<\/code>, <code>API key<\/code>, and <code>API secret<\/code> in the Dashboard. You\u2019ll need these to fetch the images we\u2019ll drag around. Make a <code>.env<\/code> file in the root of your project similar to this to hold those values:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># .env<\/span>\nCLOUDINARY_API_KEY=<span class=\"hljs-number\">0428567402670<\/span>\nCLOUDINARY_API_SECRET=hg92hgn9u2ngi24i\nCLOUDINARY_CLOUD_NAME=ojwgfro\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>One last thing we need to do is install the packages we\u2019ll be working with. Run the following command to do that:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm i express cors axios vuedraggable\n<\/code><\/span><\/pre>\n<p>The reason we need some of these packages is that we\u2019re going to make a tiny proxy app that makes the request to the Cloudinary API. You can\u2019t call this API directly from the front-end because it would expose your API secret, allowing anyone to make requests to your Cloudinary account. So we\u2019re going to start by making this proxy.<\/p>\n<h2>Making the Cloudinary request for the images<\/h2>\n<p>In the root of your project, add a new file called <code>proxy.js<\/code> and add the following code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ proxy.js<\/span>\n<span class=\"hljs-keyword\">const<\/span> express = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'express'<\/span>);\n<span class=\"hljs-keyword\">const<\/span> cors = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'cors'<\/span>);\n<span class=\"hljs-keyword\">const<\/span> axios = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'axios'<\/span>);\n\n<span class=\"hljs-keyword\">const<\/span> app = express();\n<span class=\"hljs-keyword\">const<\/span> port = <span class=\"hljs-number\">3004<\/span>;\n\napp.use(cors());\n\napp.get(<span class=\"hljs-string\">'\/images'<\/span>, <span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> results = <span class=\"hljs-keyword\">await<\/span> axios.get(\n    <span class=\"hljs-string\">`https:\/\/api.cloudinary.com\/v1_1\/<span class=\"hljs-subst\">${process.env.CLOUDINARY_CLOUD_NAME}<\/span>\/resources\/image`<\/span>,\n      {\n        <span class=\"hljs-attr\">headers<\/span>: {\n        <span class=\"hljs-attr\">Authorization<\/span>: <span class=\"hljs-string\">`Basic <span class=\"hljs-subst\">${Buffer.<span class=\"hljs-keyword\">from<\/span>(\n          process.env.CLOUDINARY_API_KEY +\n          <span class=\"hljs-string\">\":\"<\/span> +\n          process.env.CLOUDINARY_API_SECRET\n        ).toString(<span class=\"hljs-string\">\"base64\"<\/span>)}<\/span>`<\/span>,\n        },\n      }\n    ).then(<span class=\"hljs-function\">(<span class=\"hljs-params\">response<\/span>) =&gt;<\/span> {\n        <span class=\"hljs-keyword\">const<\/span> { resources } = response.data;\n\n        <span class=\"hljs-keyword\">const<\/span> allImgs = resources.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">resource<\/span>) =&gt;<\/span> ({\n            <span class=\"hljs-attr\">url<\/span>: resource.secure_url,\n            <span class=\"hljs-attr\">title<\/span>: resource.public_id,\n        }));\n    \n        res.json({<span class=\"hljs-attr\">images<\/span>: allImgs});\n    });\n});\n\napp.listen(port, () =&gt; {\n    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`Proxy listening on port <span class=\"hljs-subst\">${port}<\/span>`<\/span>);\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We start by importing a few packages and setting up the Express app. Then we create a GET endpoint that makes the Cloudinary API request and fetches the data we need. The Cloudinary API uses those credentials we got from the dashboard earlier. Then we handle the response and get the values we need from it to send to our Vue front-end.<\/p>\n<p>To wrap up this proxy, we listen to the app on the defined <code>port<\/code> and print a message to the console so we know it\u2019s working. That\u2019s all we need to get our Cloudinary images. So let\u2019s turn our attention to the front-end.<\/p>\n<h2>Render the images<\/h2>\n<p>A new Vue app comes with a good amount of boilerplate and we\u2019re going to take advantage of that. The only file we\u2019ll need to edit is <code>src &gt; components &gt; HelloWorld.vue<\/code>. This will hold the code that fetches images from our proxy, render them, and let us drag them around. So open the <code>HelloWorld.vue<\/code> file and replace all of the contents with this code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\/\/ HelloWorld.vue\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"hello\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>{{ msg }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">draggable<\/span>\n      <span class=\"hljs-attr\">:list<\/span>=<span class=\"hljs-string\">\"images\"<\/span>\n      <span class=\"hljs-attr\">item-key<\/span>=<span class=\"hljs-string\">\"title\"<\/span>\n      @<span class=\"hljs-attr\">start<\/span>=<span class=\"hljs-string\">\"drag=true\"<\/span>\n      @<span class=\"hljs-attr\">end<\/span>=<span class=\"hljs-string\">\"drag=false\"<\/span>\n    &gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span> #<span class=\"hljs-attr\">item<\/span>=<span class=\"hljs-string\">\"{element}\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"element.url\"<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"150\"<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"150\"<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">draggable<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n<span class=\"hljs-keyword\">import<\/span> draggable <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vuedraggable'<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> {\n  <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'HelloWorld'<\/span>,\n  <span class=\"hljs-attr\">props<\/span>: {\n    <span class=\"hljs-attr\">msg<\/span>: <span class=\"hljs-built_in\">String<\/span>\n  },\n  <span class=\"hljs-attr\">components<\/span>: {\n      draggable,\n  },\n  data() {\n    <span class=\"hljs-keyword\">return<\/span> {\n      <span class=\"hljs-attr\">drag<\/span>: <span class=\"hljs-literal\">false<\/span>,\n      <span class=\"hljs-attr\">images<\/span>: &#91;]\n    }\n  },\n  <span class=\"hljs-attr\">methods<\/span>: {\n    <span class=\"hljs-keyword\">async<\/span> getImages() {\n      <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">\"http:\/\/localhost:3004\/images\"<\/span>).then(<span class=\"hljs-keyword\">async<\/span> (data) =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> imageData = (<span class=\"hljs-keyword\">await<\/span> data.json()).images;\n        <span class=\"hljs-keyword\">this<\/span>.images = imageData;\n      });\n    }\n  },\n  mounted() {\n    <span class=\"hljs-keyword\">this<\/span>.getImages()\n  }\n}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-comment\">&lt;!-- Add \"scoped\" attribute to limit CSS to this component only --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span> <span class=\"hljs-attr\">scoped<\/span>&gt;<\/span><span class=\"css\">\n<span class=\"hljs-selector-tag\">h3<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">40px<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span>;\n}\n<span class=\"hljs-selector-tag\">ul<\/span> {\n  <span class=\"hljs-attribute\">list-style-type<\/span>: none;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0<\/span>;\n}\n<span class=\"hljs-selector-tag\">li<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: inline-block;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">10px<\/span>;\n}\n<span class=\"hljs-selector-tag\">a<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#42b983<\/span>;\n}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019ll start by walking through what\u2019s going on in the <code>&lt;script&gt;<\/code> first and come back to the <code>&lt;template&gt;<\/code> in a bit. Everything in the <code>&lt;script&gt;<\/code> handles the logic, data, and functions that get called. We start by importing the <code>draggable<\/code> component from a package we installed earlier. Then we define the <code>props<\/code> for the <code>HelloWorld<\/code> component, which is some leftover from the boilerplate. This allows us to pass a <code>msg<\/code> to the component when it\u2019s called in <code>App.vue<\/code>.<\/p>\n<p>Next, we add <code>draggable<\/code> to <code>components<\/code> so that it will be accessible when we\u2019re ready to render our images in the <code>&lt;template&gt;<\/code>. Then we set up the <code>data<\/code> the app will use. These are our state variables. <code>drag<\/code> is how we\u2019ll keep track of when a specific element is being moved around and <code>images<\/code> is the array that will store the images we fetch from the Cloudinary API.<\/p>\n<h3>Fetch images from the Cloudinary proxy<\/h3>\n<p>The <code>methods<\/code> contains all of the functions that we want to use in this component. We only have <code>getImages<\/code> here and it\u2019s an async function that calls the proxy app we created. It returns the image data and updates the <code>images<\/code> state we declared. Next, there is the <code>mounted<\/code> lifecycle method. This method executes on the initial page load of a Vue app. We\u2019re getting the images from the proxy each time this page is initially rendered.<\/p>\n<p>That covers everything happening in the <code>&lt;script&gt;<\/code>. Now we can discuss the actual drag and drop implementation displayed to users.<\/p>\n<h3>Add drag and drop functionality<\/h3>\n<p>Let\u2019s look at the <code>&lt;template&gt;<\/code> at the top of the file to cover what gets rendered to the user. There are only 2 main elements: the <code>&lt;div&gt;<\/code> that displays the <code>msg<\/code> prop passed to the component and <code>&lt;draggable&gt;<\/code> which has a few props we need to set. First, we set the <code>:list<\/code> prop to our <code>images<\/code> state to loop through all of the images and make them draggable. We\u2019re using <code>:list<\/code> instead of <code>:model<\/code> so that the order of images updates when they get moved.<\/p>\n<p>Then we define the <code>key<\/code> as the image title for the elements we\u2019re about to generate. Finally, we toggle the drag\/drop state based on our <code>drag<\/code> state variable. Inside of <code>&lt;draggable&gt;<\/code>, there\u2019s another <code>&lt;template&gt;<\/code> with the <code>#item<\/code> defined as <code>element<\/code>. This <code>element<\/code> is the current object from the <code>images<\/code> array. That\u2019s how we\u2019re able to display all of the images to the user.<\/p>\n<p>Now run your app with and proxy with the following commands:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">npm run serve <span class=\"hljs-comment\"># starts Vue app<\/span>\nnode proxy.js <span class=\"hljs-comment\"># starts Express proxy<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You should be able to see all of the images load and change their order.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1660670515\/e-603fc55d218a650069f5228b\/js8x7nak7xvlziwngtit.png\" alt=\"all of the images on the page\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1216\"\/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1660670610\/e-603fc55d218a650069f5228b\/zfob0wkk1ffifwzkdrwa.png\" alt=\"image being dragged\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1219\"\/><\/p>\n<p>This gives you some simple drag and drop functionality that you can expand on to fit any Vue app you\u2019re working with.<\/p>\n<h2>Finished code<\/h2>\n<p>You can take a look at the complete code in <a href=\"https:\/\/github.com\/flippedcoder\/media-projects\/tree\/main\/camera-filter\">the <code>camera-filter<\/code> folder of this repo<\/a>. Or you can check it out in <a href=\"https:\/\/codesandbox.io\/s\/keen-burnell-vtco58\">this Code Sandbox<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/keen-burnell-vtco58?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"keen-burnell-vtco58\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Conclusion<\/h2>\n<p>It\u2019s always good to learn about different frameworks and how they work compared to ones you\u2019re more familiar with. Implementing drag and drop functionality is a common request for all kinds of applications. Learning how to do these kinds of common tasks in different frameworks or using different packages or approaches will help you grow into a more senior developer quickly.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28188,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,371,315],"class_list":["post-28187","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-under-review","tag-vue"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Implement Drag and Drop on Images in Vue<\/title>\n<meta name=\"description\" content=\"Let&#039;s build a simple drag and drop component in Vue using the `vuedraggable` package.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Implement Drag and Drop on Images in Vue\" \/>\n<meta property=\"og:description\" content=\"Let&#039;s build a simple drag and drop component in Vue using the `vuedraggable` package.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-11-14T08:44:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-16T15:53:05+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Implement Drag and Drop on Images in Vue\",\"datePublished\":\"2022-11-14T08:44:53+00:00\",\"dateModified\":\"2025-02-16T15:53:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"Under Review\",\"Vue\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\",\"name\":\"Implement Drag and Drop on Images in Vue\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA\",\"datePublished\":\"2022-11-14T08:44:53+00:00\",\"dateModified\":\"2025-02-16T15:53:05+00:00\",\"description\":\"Let's build a simple drag and drop component in Vue using the `vuedraggable` package.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA\",\"width\":4751,\"height\":3002},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Implement Drag and Drop on Images in Vue\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Implement Drag and Drop on Images in Vue","description":"Let's build a simple drag and drop component in Vue using the `vuedraggable` package.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/","og_locale":"en_US","og_type":"article","og_title":"Implement Drag and Drop on Images in Vue","og_description":"Let's build a simple drag and drop component in Vue using the `vuedraggable` package.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-11-14T08:44:53+00:00","article_modified_time":"2025-02-16T15:53:05+00:00","twitter_card":"summary_large_image","twitter_image":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/"},"author":{"name":"","@id":""},"headline":"Implement Drag and Drop on Images in Vue","datePublished":"2022-11-14T08:44:53+00:00","dateModified":"2025-02-16T15:53:05+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","keywords":["Guest Post","Image","Under Review","Vue"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/","name":"Implement Drag and Drop on Images in Vue","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","datePublished":"2022-11-14T08:44:53+00:00","dateModified":"2025-02-16T15:53:05+00:00","description":"Let's build a simple drag and drop component in Vue using the `vuedraggable` package.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","width":4751,"height":3002},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-on-images-in-vue\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Implement Drag and Drop on Images in Vue"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681923593\/Web_Assets\/blog\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07\/e6761e021e376f23955950c6794cdc62cd724860-4751x3002-1_2818899f07.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28187"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28187\/revisions"}],"predecessor-version":[{"id":36836,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28187\/revisions\/36836"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28188"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}