{"id":31285,"date":"2025-10-08T07:40:56","date_gmt":"2025-10-08T04:40:56","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=31285"},"modified":"2025-10-08T07:40:56","modified_gmt":"2025-10-08T04:40:56","slug":"vue-js-ile-basit-ozel-dosya-secici-olusturma","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/","title":{"rendered":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma"},"content":{"rendered":"<p><body><\/p>\n<h2>Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma<\/h2>\n<h3>Giri\u015f: Neden \u00d6zel Bir Dosya Se\u00e7iciye \u0130htiya\u00e7 Duyar\u0131z?<\/h3>\n<p>Web uygulamalar\u0131nda kullan\u0131c\u0131lar\u0131n dosya y\u00fcklemesi, foto\u011fraf eklemesi veya belge g\u00f6ndermesi olduk\u00e7a yayg\u0131n bir gereksinimdir. Bu t\u00fcr etkile\u015fimler i\u00e7in taray\u0131c\u0131lar bize yerle\u015fik bir <code>input type=\"file\"<\/code> \u00f6\u011fesi sunar. Ancak, bu yerel dosya se\u00e7icinin g\u00f6r\u00fcn\u00fcm\u00fc ve hissi, taray\u0131c\u0131dan taray\u0131c\u0131ya farkl\u0131l\u0131k g\u00f6sterir ve genellikle uygulama tasar\u0131m\u0131m\u0131zla uyumlu de\u011fildir. Varsay\u0131lan stilini de\u011fi\u015ftirmek olduk\u00e7a zordur ve \u00e7o\u011fu zaman s\u0131n\u0131rl\u0131 kal\u0131r\u0131z. Kullan\u0131c\u0131 deneyimi (UX) a\u00e7\u0131s\u0131ndan da, sadece &#8220;Dosya Se\u00e7&#8221; yazan bir d\u00fc\u011fme yerine, daha interaktif, g\u00f6rsel olarak \u00e7ekici ve bilgilendirici bir se\u00e7ici sunmak isteyebiliriz. \u00d6rne\u011fin, se\u00e7ilen dosyalar\u0131n adlar\u0131n\u0131, boyutlar\u0131n\u0131 g\u00f6stermek, k\u00fc\u00e7\u00fck resim \u00f6nizlemeleri sunmak veya s\u00fcr\u00fckle-b\u0131rak (drag-and-drop) i\u015flevselli\u011fi eklemek gibi \u00f6zellikler, standart dosya se\u00e7ici ile do\u011frudan m\u00fcmk\u00fcn de\u011fildir.<\/p>\n<p>\u0130\u015fte tam da bu noktada, Vue.js gibi modern bir JavaScript \u00e7er\u00e7evesi devreye girer. Vue.js&#8217;in reaktif do\u011fas\u0131, bile\u015fen tabanl\u0131 yap\u0131s\u0131 ve esnek DOM manip\u00fclasyon yetenekleri, \u00f6zel ve tamamen kontrol edilebilir bir dosya se\u00e7ici bile\u015feni olu\u015fturmak i\u00e7in m\u00fckemmel bir ara\u00e7t\u0131r. Bu makalede, Vue.js kullanarak, sadece temel i\u015flevselli\u011fi sa\u011flamakla kalmay\u0131p ayn\u0131 zamanda tamamen \u00f6zelle\u015ftirilebilir ve kullan\u0131c\u0131 dostu bir dosya se\u00e7ici bile\u015fenini ad\u0131m ad\u0131m nas\u0131l olu\u015fturaca\u011f\u0131m\u0131z\u0131 inceleyece\u011fiz. Native dosya giri\u015finin s\u0131n\u0131rlamalar\u0131ndan ba\u015flayarak, Vue.js&#8217;in temel \u00f6zelliklerini kullanarak nas\u0131l bir \u00e7\u00f6z\u00fcm geli\u015ftirece\u011fimizi, dosya se\u00e7imi, \u00f6nizleme, do\u011frulama ve hatta s\u00fcr\u00fckle-b\u0131rak i\u015flevselli\u011fini nas\u0131l entegre edece\u011fimizi detayl\u0131 bir \u015fekilde ele alaca\u011f\u0131z. Amac\u0131m\u0131z, uygulaman\u0131z\u0131n esteti\u011fi ve kullan\u0131c\u0131 deneyimiyle kusursuz bir \u015fekilde b\u00fct\u00fcnle\u015fen, basit ama g\u00fc\u00e7l\u00fc bir dosya se\u00e7ici olu\u015fturmakt\u0131r.<\/p>\n<h3>Yerel <code>input type=\"file\"<\/code> \u00d6\u011fesinin S\u0131n\u0131rlamalar\u0131<\/h3>\n<p>Web geli\u015ftiricileri olarak, form elemanlar\u0131n\u0131 \u00f6zelle\u015ftirme konusunda s\u0131k s\u0131k zorluklarla kar\u015f\u0131la\u015f\u0131r\u0131z. <code>input type=\"file\"<\/code> da bu elemanlardan biridir. Temel i\u015flevselli\u011fi sa\u011flamas\u0131na ra\u011fmen, sundu\u011fu k\u0131s\u0131tlamalar nedeniyle \u00e7o\u011fu zaman alternatif \u00e7\u00f6z\u00fcmlere y\u00f6neliriz.<\/p>\n<h4>Varsay\u0131lan G\u00f6r\u00fcn\u00fcm ve Stil Uyumsuzlu\u011fu<\/h4>\n<p><code>input type=\"file\"<\/code> \u00f6\u011fesinin en belirgin s\u0131n\u0131rlamas\u0131, taray\u0131c\u0131lar aras\u0131 tutars\u0131z ve genellikle estetik olmayan varsay\u0131lan g\u00f6r\u00fcn\u00fcm\u00fcd\u00fcr. Her taray\u0131c\u0131, bu \u00f6\u011feyi kendi i\u015fletim sistemi veya UI y\u00f6nergelerine g\u00f6re render eder. Bu durum, web uygulaman\u0131z\u0131n genel tasar\u0131m diline uymayan, yabanc\u0131 duran bir elemanla sonu\u00e7lanabilir. CSS ile bu \u00f6\u011feyi stilize etmek de olduk\u00e7a k\u0131s\u0131tl\u0131d\u0131r. Genellikle sadece font, renk gibi temel \u00f6zellikler \u00fczerinde kontrol\u00fcm\u00fcz olurken, d\u00fc\u011fmenin \u015feklini, boyutunu, ikonunu veya i\u00e7erisindeki metni tamamen de\u011fi\u015ftirmek neredeyse imkans\u0131zd\u0131r. Arka plan rengi veya kenarl\u0131k gibi \u00f6zellikler \u00fczerinde yap\u0131lan de\u011fi\u015fiklikler bile \u00e7o\u011fu zaman beklendi\u011fi gibi \u00e7al\u0131\u015fmaz veya t\u00fcm taray\u0131c\u0131larda tutarl\u0131 bir sonu\u00e7 vermez. Bu durum, markan\u0131z\u0131n kimli\u011fini yans\u0131tan veya belirli bir kullan\u0131c\u0131 deneyimi ak\u0131\u015f\u0131na sahip uygulamalar i\u00e7in b\u00fcy\u00fck bir dezavantajd\u0131r.<\/p>\n<h4>S\u0131n\u0131rl\u0131 Kullan\u0131c\u0131 Deneyimi<\/h4>\n<p>Varsay\u0131lan dosya se\u00e7ici, kullan\u0131c\u0131lara se\u00e7ilen dosyalar hakk\u0131nda \u00e7ok az g\u00f6rsel geri bildirim sunar. Bir dosya se\u00e7ildi\u011finde, genellikle sadece d\u00fc\u011fmenin yan\u0131nda k\u00fc\u00e7\u00fck bir metin (\u00f6rne\u011fin, &#8220;1 dosya se\u00e7ildi&#8221; veya dosyan\u0131n ad\u0131) g\u00f6r\u00fcn\u00fcr. Ancak, birden fazla dosya se\u00e7ildi\u011finde, her bir dosyan\u0131n ad\u0131n\u0131, boyutunu veya bir \u00f6nizlemesini g\u00f6rmek gibi geli\u015fmi\u015f \u00f6zellikler yerle\u015fik olarak mevcut de\u011fildir. Kullan\u0131c\u0131lar\u0131n se\u00e7tikleri dosyalar\u0131 kolayca g\u00f6zden ge\u00e7irebilmesi, yanl\u0131\u015fl\u0131kla se\u00e7ilen bir dosyay\u0131 kald\u0131rabilmesi veya dosya t\u00fcr\u00fc\/boyutu gibi k\u0131s\u0131tlamalar hakk\u0131nda an\u0131nda geri bildirim alabilmesi, modern web uygulamalar\u0131n\u0131n beklenen \u00f6zellikleridir. Yerel dosya se\u00e7ici bu t\u00fcr interaktif \u00f6zelliklerden yoksundur.<\/p>\n<h4>Programatik Kontrol Zorluklar\u0131<\/h4>\n<p><code>input type=\"file\"<\/code> \u00f6\u011fesini JavaScript ile programatik olarak tetiklemek m\u00fcmk\u00fcnd\u00fcr (\u00f6rne\u011fin, gizli bir input&#8217;a t\u0131klayarak), ancak se\u00e7ilen dosyalar\u0131 i\u015flemek i\u00e7in genellikle <code>change<\/code> olay\u0131na g\u00fcvenmek zorunday\u0131z. Dosya se\u00e7imi tamamland\u0131ktan sonra <code>event.target.files<\/code> \u00fczerinden <code>FileList<\/code> objesine eri\u015firiz. Bu obje, <code>File<\/code> objelerini i\u00e7erir ve her bir <code>File<\/code> objesi dosya ad\u0131, boyutu, t\u00fcr\u00fc gibi bilgileri bar\u0131nd\u0131r\u0131r. Ancak, bu bilgileri bir UI&#8217;da g\u00f6stermek veya \u00f6zel do\u011frulamalar yapmak tamamen geli\u015ftiricinin sorumlulu\u011fundad\u0131r. Ayr\u0131ca, s\u00fcr\u00fckle-b\u0131rak gibi geli\u015fmi\u015f etkile\u015fimler i\u00e7in ayr\u0131 bir kodlama gerektirir ve yerle\u015fik olarak sunulmaz. Bu s\u0131n\u0131rlamalar, daha esnek ve kontrol edilebilir bir dosya se\u00e7ici bile\u015feni olu\u015fturma ihtiyac\u0131n\u0131 do\u011furur.<\/p>\n<h3>Vue.js ile Temel Kavramlar<\/h3>\n<p>\u00d6zel bir dosya se\u00e7ici bile\u015feni olu\u015ftururken, Vue.js&#8217;in baz\u0131 temel \u00f6zelliklerinden yararlanaca\u011f\u0131z. Bu \u00f6zellikler, bile\u015fenimizin reaktif, y\u00f6netilebilir ve yeniden kullan\u0131labilir olmas\u0131n\u0131 sa\u011flayacakt\u0131r.<\/p>\n<h4>Vue Bile\u015fenleri (Single File Components &#8211; SFC)<\/h4>\n<p>Vue.js, uygulamalar\u0131 k\u00fc\u00e7\u00fck, ba\u011f\u0131ms\u0131z ve yeniden kullan\u0131labilir bile\u015fenlere ay\u0131rma felsefesini benimser. Tek Dosya Bile\u015fenleri (SFC&#8217;ler), <code>.vue<\/code> uzant\u0131l\u0131 dosyalar olarak gelir ve bir bile\u015fenin \u015fablonunu (<code><template><\/code>), beti\u011fini (<code><script><\/code>) ve stilini (<code><\/p>\n<style><\/code>) tek bir dosyada birle\u015ftirir. Bu yap\u0131, bile\u015fenlerin geli\u015ftirilmesini ve bak\u0131m\u0131n\u0131 son derece kolayla\u015ft\u0131r\u0131r. Dosya se\u00e7icimizi de bir SFC olarak olu\u015fturaca\u011f\u0131z.<\/p>\n<h4>Reaktif Veri (<code>data()<\/code>)<\/h4>\n<p>Vue.js'in temel ta\u015f\u0131 reaktivitedir. Bir bile\u015fenin <code>data()<\/code> fonksiyonu taraf\u0131ndan d\u00f6nd\u00fcr\u00fclen nesnedeki t\u00fcm \u00f6zellikler reaktif hale getirilir. Bu, bu \u00f6zelliklerin de\u011ferleri de\u011fi\u015fti\u011finde, Vue'nun otomatik olarak DOM'u g\u00fcncelleyece\u011fi anlam\u0131na gelir. Dosya se\u00e7icimizde, se\u00e7ilen dosyalar\u0131, hata mesajlar\u0131n\u0131 veya y\u00fckleme durumunu tutmak i\u00e7in reaktif veri \u00f6zelliklerini kullanaca\u011f\u0131z. \u00d6rne\u011fin, <code>selectedFiles<\/code> ad\u0131nda bir dizi, kullan\u0131c\u0131n\u0131n se\u00e7ti\u011fi t\u00fcm dosyalar\u0131 depolayacakt\u0131r.<\/p>\n<h4>Olay Dinleyicileri (<code>v-on<\/code> veya <code>@<\/code>)<\/h4>\n<p>Vue.js, DOM olaylar\u0131n\u0131 dinlemek ve bunlara tepki vermek i\u00e7in <code>v-on<\/code> direktifini veya onun k\u0131sa yaz\u0131m\u0131 olan <code>@<\/code> sembol\u00fcn\u00fc sunar. Dosya se\u00e7icimizde, bir d\u00fc\u011fmeye t\u0131kland\u0131\u011f\u0131nda (gizli <code>input type=\"file\"<\/code>'\u0131 tetiklemek i\u00e7in) veya <code>input type=\"file\"<\/code>'\u0131n <code>change<\/code> olay\u0131 tetiklendi\u011finde (kullan\u0131c\u0131 dosya se\u00e7ti\u011finde) bu olay dinleyicilerini kullanaca\u011f\u0131z. S\u00fcr\u00fckle-b\u0131rak i\u015flevselli\u011fi i\u00e7in ise <code>dragover<\/code>, <code>dragleave<\/code> ve <code>drop<\/code> gibi olaylar\u0131 dinleyece\u011fiz.<\/p>\n<h4>Referanslar (<code>ref<\/code>)<\/h4>\n<p>Vue.js, genellikle do\u011frudan DOM manip\u00fclasyonundan ka\u00e7\u0131nmam\u0131z\u0131 te\u015fvik eder ve reaktif veri ak\u0131\u015f\u0131 ile \u00e7al\u0131\u015fmay\u0131 \u00f6nerir. Ancak, baz\u0131 durumlarda (\u00f6zellikle \u00fc\u00e7\u00fcnc\u00fc taraf k\u00fct\u00fcphanelerle entegrasyon veya yerel DOM \u00f6\u011felerini tetikleme gibi), do\u011frudan bir DOM \u00f6\u011fesine eri\u015fmemiz gerekebilir. Vue.js, bu durumlar i\u00e7in <code>ref<\/code> \u00f6zelli\u011fini sunar. Bir DOM \u00f6\u011fesine veya bile\u015fene <code>ref<\/code> \u00f6zelli\u011fi ekleyerek, bile\u015fenin <code>this.$refs<\/code> objesi \u00fczerinden ona eri\u015febiliriz. Dosya se\u00e7icimizde, gizli <code>input type=\"file\"<\/code> \u00f6\u011fesini programatik olarak t\u0131klamak i\u00e7in bu y\u00f6ntemi kullanaca\u011f\u0131z.<\/p>\n<h4>Y\u00f6ntemler (<code>methods<\/code>)<\/h4>\n<p>Bile\u015fenlerin davran\u0131\u015f\u0131n\u0131 tan\u0131mlamak i\u00e7in <code>methods<\/code> se\u00e7ene\u011fini kullan\u0131r\u0131z. <code>methods<\/code> objesi i\u00e7erisinde tan\u0131mlanan fonksiyonlar, bile\u015fenin \u015fablonundan veya di\u011fer y\u00f6ntemlerinden \u00e7a\u011fr\u0131labilir. Dosya se\u00e7me i\u015flemini ba\u015flatmak, se\u00e7ilen dosyalar\u0131 i\u015flemek, dosyalar\u0131 kald\u0131rmak veya do\u011frulama yapmak gibi t\u00fcm mant\u0131ksal i\u015flemlerimizi <code>methods<\/code> i\u00e7erisinde tan\u0131mlayaca\u011f\u0131z.<\/p>\n<h4>Ko\u015fullu Render Etme (<code>v-if<\/code>, <code>v-for<\/code>)<\/h4>\n<p>Vue.js, belirli ko\u015fullara ba\u011fl\u0131 olarak \u00f6\u011feleri render etmek veya bir liste \u00fczerinden yinelemek i\u00e7in <code>v-if<\/code>, <code>v-else-if<\/code>, <code>v-else<\/code> ve <code>v-for<\/code> direktiflerini sa\u011flar. Se\u00e7ilen dosyalar\u0131n listesini g\u00f6stermek i\u00e7in <code>v-for<\/code>'u, hata mesajlar\u0131n\u0131 veya dosya \u00f6nizlemelerini ko\u015fullu olarak g\u00f6stermek i\u00e7in ise <code>v-if<\/code>'i kullanaca\u011f\u0131z. Bu direktifler, bile\u015fenimizin UI's\u0131n\u0131 dinamik ve duruma ba\u011fl\u0131 hale getirmemize olanak tan\u0131r.<\/p>\n<h3>\u00d6zel Dosya Se\u00e7ici Bile\u015feni Olu\u015fturma<\/h3>\n<p>\u015eimdi Vue.js'in temel kavramlar\u0131n\u0131 kullanarak <code>CustomFileSelector.vue<\/code> ad\u0131nda bir bile\u015fen olu\u015ftural\u0131m. Bu bile\u015fen, kullan\u0131c\u0131lar\u0131n dosya se\u00e7mesini, se\u00e7ilen dosyalar\u0131 g\u00f6r\u00fcnt\u00fclemesini ve hatta dosyalar\u0131 s\u00fcr\u00fckleyip b\u0131rakmas\u0131n\u0131 sa\u011flayacak.<\/p>\n<h4>Bile\u015fen \u015eablonu (<code><template><\/code>)<\/h4>\n<p>\u015eablonumuz, kullan\u0131c\u0131lar\u0131n etkile\u015fimde bulunaca\u011f\u0131 g\u00f6r\u00fcn\u00fcr k\u0131sm\u0131 ve gizli <code>input type=\"file\"<\/code> \u00f6\u011fesini i\u00e7erecek. Ayr\u0131ca, se\u00e7ilen dosyalar\u0131 listeleyecek bir alan ve hata mesajlar\u0131 i\u00e7in bir yerimiz olacak.<\/p>\n<pre><code class=\"language-vue\"><template>\n  <div\n    class=\"file-selector-container\"\n    :class=\"{ 'drag-over': isDragOver }\"\n    @dragover.prevent=\"handleDragOver\"\n    @dragleave=\"handleDragLeave\"\n    @drop.prevent=\"handleDrop\"\n  >\n    <input\n      type=\"file\"\n      ref=\"fileInput\"\n      :multiple=\"multiple\"\n      :accept=\"accept\"\n      @change=\"handleFileChange\"\n      style=\"display: none;\"\n    \/>\n\n    <div class=\"file-selector-area\" @click=\"triggerFileInput\">\n      <p v-if=\"!selectedFiles.length\">\n        Dosya se\u00e7mek i\u00e7in t\u0131klay\u0131n veya dosyalar\u0131 buraya s\u00fcr\u00fckleyin.\n      <\/p>\n      <div v-else class=\"selected-files-summary\">\n        <p>{{ selectedFiles.length }} dosya se\u00e7ildi.<\/p>\n        <button @click.stop=\"triggerFileInput\" class=\"add-more-button\">\n          Daha Fazla Dosya Ekle\n        <\/button>\n      <\/div>\n    <\/div>\n\n    <div v-if=\"errorMessage\" class=\"error-message\">\n      {{ errorMessage }}\n    <\/div>\n\n    <ul v-if=\"selectedFiles.length\" class=\"file-list\">\n      <li v-for=\"(file, index) in selectedFiles\" :key=\"file.name + file.size + index\" class=\"file-item\">\n        <div class=\"file-info\">\n          <img v-if=\"file.preview\" :src=\"file.preview\" class=\"file-thumbnail\" alt=\"File preview\" \/>\n          <span class=\"file-name\">{{ file.name }}<\/span>\n          <span class=\"file-size\">({{ formatFileSize(file.size) }})<\/span>\n        <\/div>\n        <button @click=\"removeFile(index)\" class=\"remove-button\">X<\/button>\n      <\/li>\n    <\/ul>\n  <\/div>\n<\/template><\/code><\/pre>\n<h4>Bile\u015fen Beti\u011fi (<code><script><\/code>)<\/h4>\n<p>Beti\u011fimiz, reaktif verileri, y\u00f6ntemleri ve bile\u015fen ya\u015fam d\u00f6ng\u00fcs\u00fc kancalar\u0131n\u0131 i\u00e7erecek. Burada dosya i\u015fleme, do\u011frulama ve s\u00fcr\u00fckle-b\u0131rak mant\u0131\u011f\u0131n\u0131 y\u00f6netece\u011fiz.<\/p>\n<pre><code class=\"language-vue\"><script>\nexport default {\n  props: {\n    multiple: {\n      type: Boolean,\n      default: false,\n    },\n    accept: {\n      type: String,\n      default: \"<em>\/<\/em>\", \/\/ T\u00fcm dosya t\u00fcrlerini kabul et\n    },\n    maxFileSize: {\n      type: Number,\n      default: 5 <em> 1024 <\/em> 1024, \/\/ Varsay\u0131lan: 5MB\n    },\n    maxFiles: {\n      type: Number,\n      default: 0, \/\/ 0 s\u0131n\u0131rs\u0131z dosya anlam\u0131na gelir\n    },\n  },\n  data() {\n    return {\n      selectedFiles: [],\n      errorMessage: \"\",\n      isDragOver: false,\n    };\n  },\n  methods: {\n    triggerFileInput() {\n      this.$refs.fileInput.click();\n    },\n    handleFileChange(event) {\n      const files = event.target.files;\n      this.processFiles(files);\n      \/\/ input'u temizle ki ayn\u0131 dosyay\u0131 tekrar se\u00e7ebilsin\n      event.target.value = '';\n    },\n    handleDragOver() {\n      this.isDragOver = true;\n    },\n    handleDragLeave() {\n      this.isDragOver = false;\n    },\n    handleDrop(event) {\n      this.isDragOver = false;\n      const files = event.dataTransfer.files;\n      this.processFiles(files);\n    },\n    processFiles(newFiles) {\n      this.errorMessage = \"\"; \/\/ Hata mesaj\u0131n\u0131 s\u0131f\u0131rla\n\n      if (!newFiles.length) return;\n\n      let validFiles = [];\n      let totalFilesAfterSelection = this.selectedFiles.length;\n\n      for (let i = 0; i < newFiles.length; i++) {\n        const file = newFiles[i];\n\n        \/\/ Dosya say\u0131s\u0131 kontrol\u00fc\n        if (this.maxFiles > 0 && totalFilesAfterSelection >= this.maxFiles) {\n          this.errorMessage = <code>En fazla ${this.maxFiles} dosya se\u00e7ebilirsiniz.<\/code>;\n          break;\n        }\n\n        \/\/ Dosya t\u00fcr\u00fc kontrol\u00fc\n        if (this.accept !== \"<em>\/<\/em>\" && !file.type.match(new RegExp(this.accept.replace(\/\\<em>\/g, '.<\/em>')))) {\n          this.errorMessage = <code>Sadece ${this.accept} t\u00fcr\u00fcnde dosyalar kabul edilir.<\/code>;\n          continue;\n        }\n\n        \/\/ Dosya boyutu kontrol\u00fc\n        if (file.size > this.maxFileSize) {\n          this.errorMessage = <code>\"${file.name}\" dosyas\u0131 \u00e7ok b\u00fcy\u00fck. Maksimum boyut: ${this.formatFileSize(this.maxFileSize)}.<\/code>;\n          continue;\n        }\n\n        \/\/ Ayn\u0131 dosyan\u0131n zaten se\u00e7ili olup olmad\u0131\u011f\u0131n\u0131 kontrol et (isim ve boyut ile)\n        const isDuplicate = this.selectedFiles.some(\n          (existingFile) =>\n            existingFile.name === file.name && existingFile.size === file.size\n        );\n        if (isDuplicate) {\n          this.errorMessage = <code>\"${file.name}\" dosyas\u0131 zaten se\u00e7ili.<\/code>;\n          continue;\n        }\n\n        \/\/ \u00d6nizleme olu\u015ftur\n        if (file.type.startsWith(\"image\/\")) {\n          const reader = new FileReader();\n          reader.onload = (e) => {\n            file.preview = e.target.result;\n            \/\/ Reaktivite i\u00e7in Vue'ya bildirim\n            this.$set(file, 'preview', e.target.result);\n          };\n          reader.readAsDataURL(file);\n        } else {\n          file.preview = null; \/\/ Resim olmayan dosyalar i\u00e7in \u00f6nizleme yok\n        }\n\n        validFiles.push(file);\n        totalFilesAfterSelection++; \/\/ Ba\u015far\u0131l\u0131 eklenen dosyalar\u0131 say\n      }\n\n      if (this.multiple) {\n        this.selectedFiles = [...this.selectedFiles, ...validFiles];\n      } else {\n        this.selectedFiles = validFiles.length ? [validFiles[0]] : [];\n      }\n      this.$emit(\"files-selected\", this.selectedFiles);\n    },\n    removeFile(index) {\n      const removedFile = this.selectedFiles.splice(index, 1);\n      this.$emit(\"file-removed\", removedFile[0]);\n      this.errorMessage = \"\"; \/\/ Dosya kald\u0131r\u0131ld\u0131\u011f\u0131nda hata mesaj\u0131n\u0131 temizle\n    },\n    formatFileSize(bytes) {\n      if (bytes === 0) return \"0 Bytes\";\n      const k = 1024;\n      const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n      const i = Math.floor(Math.log(bytes) \/ Math.log(k));\n      return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n    },\n  },\n  watch: {\n    selectedFiles: {\n      handler(newFiles) {\n        \/\/ Bu watcher, selectedFiles de\u011fi\u015fti\u011finde d\u0131\u015far\u0131ya emit yapmak i\u00e7in kullan\u0131labilir.\n        \/\/ Ama\u00e7: Parent component'in se\u00e7ilen dosyalar\u0131 kolayca alabilmesi.\n        \/\/ this.$emit('update:modelValue', newFiles); \/\/ v-model uyumlulu\u011fu i\u00e7in\n      },\n      deep: true,\n    },\n  },\n};\n<\/script><\/code><\/pre>\n<h4>Bile\u015fen Stilleri (<code><\/p>\n<style><\/code>)<\/h4>\n<p>CSS ile bile\u015fenimizin g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc \u00f6zelle\u015ftirece\u011fiz. <code>scoped<\/code> anahtar kelimesi, stillerin sadece bu bile\u015fene \u00f6zel olmas\u0131n\u0131 sa\u011flayarak global stil \u00e7ak\u0131\u015fmalar\u0131n\u0131 \u00f6nler.<\/p>\n<pre><code class=\"language-vue\"><style scoped>\n.file-selector-container {\n  border: 2px dashed #ccc;\n  border-radius: 8px;\n  padding: 20px;\n  text-align: center;\n  cursor: pointer;\n  transition: all 0.3s ease;\n  background-color: #f9f9f9;\n  margin-bottom: 20px;\n}\n\n.file-selector-container.drag-over {\n  border-color: #007bff;\n  background-color: #e6f7ff;\n}\n\n.file-selector-area {\n  min-height: 80px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\n.file-selector-area p {\n  margin: 0;\n  color: #666;\n}\n\n.selected-files-summary {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.add-more-button {\n  background-color: #007bff;\n  color: white;\n  border: none;\n  padding: 8px 15px;\n  border-radius: 5px;\n  cursor: pointer;\n  margin-top: 10px;\n  font-size: 0.9em;\n}\n\n.add-more-button:hover {\n  background-color: #0056b3;\n}\n\n.error-message {\n  color: #dc3545;\n  margin-top: 10px;\n  font-size: 0.9em;\n}\n\n.file-list {\n  list-style: none;\n  padding: 0;\n  margin-top: 20px;\n  border-top: 1px solid #eee;\n  padding-top: 15px;\n}\n\n.file-item {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 10px 0;\n  border-bottom: 1px solid #eee;\n}\n\n.file-item:last-child {\n  border-bottom: none;\n}\n\n.file-info {\n  display: flex;\n  align-items: center;\n  flex-grow: 1;\n}\n\n.file-thumbnail {\n  width: 40px;\n  height: 40px;\n  object-fit: cover;\n  margin-right: 10px;\n  border-radius: 4px;\n  border: 1px solid #eee;\n}\n\n.file-name {\n  font-weight: bold;\n  margin-right: 10px;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  max-width: 60%; \/<em> Or adjust as needed <\/em>\/\n}\n\n.file-size {\n  color: #888;\n  font-size: 0.85em;\n}\n\n.remove-button {\n  background-color: #dc3545;\n  color: white;\n  border: none;\n  border-radius: 50%;\n  width: 25px;\n  height: 25px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 0.8em;\n  cursor: pointer;\n  flex-shrink: 0; \/<em> Butonun k\u00fc\u00e7\u00fclmesini engelle <\/em>\/\n}\n\n.remove-button:hover {\n  background-color: #c82333;\n}\n<\/style><\/code><\/pre>\n<h3>Geli\u015fmi\u015f \u00d6zellikler ve Kullan\u0131m<\/h3>\n<h4>Dosya \u00d6nizlemeleri<\/h4>\n<p><code>FileReader<\/code> API'si, web uygulamalar\u0131n\u0131n kullan\u0131c\u0131lar\u0131n yerel sistemlerindeki dosyalar\u0131n i\u00e7eri\u011fini e\u015fzamans\u0131z olarak okumas\u0131n\u0131 sa\u011flar. \u00d6zellikle resim dosyalar\u0131 i\u00e7in, <code>readAsDataURL<\/code> y\u00f6ntemi, dosyan\u0131n i\u00e7eri\u011fini bir Base64 kodlu veri URL'si olarak okur. Bu URL, do\u011frudan bir <code><img><\/code> etiketinin <code>src<\/code> \u00f6zniteli\u011fine atanarak resim \u00f6nizlemesi g\u00f6r\u00fcnt\u00fclenebilir. Yukar\u0131daki kodda, <code>processFiles<\/code> metodunda <code>file.type.startsWith(\"image\/\")<\/code> kontrol\u00fc ile bir dosyan\u0131n resim olup olmad\u0131\u011f\u0131 belirlenir ve e\u011fer resimse <code>FileReader<\/code> kullan\u0131larak bir <code>preview<\/code> URL'si olu\u015fturulur ve <code>file<\/code> objesine eklenir. Bu, reaktif bir \u00f6zellik oldu\u011fu i\u00e7in Vue otomatik olarak UI'y\u0131 g\u00fcnceller.<\/p>\n<h4>Dosya Do\u011frulama (T\u00fcr ve Boyut)<\/h4>\n<p>Dosya se\u00e7icimizin kullan\u0131c\u0131 deneyimini art\u0131rmak ve sunucu taraf\u0131nda i\u015f y\u00fck\u00fcn\u00fc azaltmak i\u00e7in istemci taraf\u0131nda dosya do\u011frulama yapmak \u00f6nemlidir.<br \/>\n<em>   <strong>Dosya T\u00fcr\u00fc Do\u011frulamas\u0131<\/strong>: <code>accept<\/code> prop'u, <code>input type=\"file\"<\/code> \u00f6\u011fesinin hangi dosya t\u00fcrlerini kabul edece\u011fini belirtir (\u00f6rne\u011fin, <code>image\/<\/em><\/code>, <code>.pdf<\/code>, <code>image\/jpeg,image\/png<\/code>). Ancak, bu sadece bir \u00f6neridir ve kullan\u0131c\u0131 \"T\u00fcm Dosyalar\" se\u00e7ene\u011fini se\u00e7erek farkl\u0131 t\u00fcrde dosyalar\u0131 se\u00e7ebilir. Bu nedenle, <code>processFiles<\/code> metodumuzda, <code>file.type<\/code> \u00f6zelli\u011fini <code>accept<\/code> prop'u ile kar\u015f\u0131la\u015ft\u0131rarak daha kat\u0131 bir do\u011frulama yapar\u0131z. <code>accept<\/code> prop'u bir regex ile e\u015fle\u015ftirilerek daha esnek bir kontrol sa\u011flan\u0131r.<br \/>\n*   <strong>Dosya Boyutu Do\u011frulamas\u0131<\/strong>: <code>maxFileSize<\/code> prop'u ile bir dosyan\u0131n kabul edilebilir maksimum boyutunu belirleriz. <code>file.size<\/code> \u00f6zelli\u011fi, dosyan\u0131n boyutunu bayt cinsinden verir. Bu de\u011feri <code>maxFileSize<\/code> ile kar\u015f\u0131la\u015ft\u0131rarak, \u00e7ok b\u00fcy\u00fck dosyalar\u0131n y\u00fcklenmesini engelleriz. <code>formatFileSize<\/code> metodu, boyutlar\u0131 daha okunabilir bir bi\u00e7imde (KB, MB vb.) g\u00f6stermek i\u00e7in kullan\u0131l\u0131r.<br \/>\n*   <strong>Dosya Say\u0131s\u0131 Do\u011frulamas\u0131<\/strong>: <code>maxFiles<\/code> prop'u ile ayn\u0131 anda se\u00e7ilebilecek maksimum dosya say\u0131s\u0131n\u0131 belirleriz. <code>processFiles<\/code> metodu, mevcut se\u00e7ili dosya say\u0131s\u0131n\u0131 ve yeni eklenen dosyalar\u0131 dikkate alarak bu s\u0131n\u0131r\u0131 a\u015fmamay\u0131 sa\u011flar.<\/p>\n<h4>S\u00fcr\u00fckle-B\u0131rak (Drag & Drop) \u0130\u015flevselli\u011fi<\/h4>\n<p>S\u00fcr\u00fckle-b\u0131rak, modern web uygulamalar\u0131nda kullan\u0131c\u0131 dostu bir \u00f6zelliktir. Bile\u015fenimiz, <code>dragover<\/code>, <code>dragleave<\/code> ve <code>drop<\/code> DOM olaylar\u0131n\u0131 dinleyerek bu i\u015flevselli\u011fi sa\u011flar:<br \/>\n*   <code>@dragover.prevent=\"handleDragOver\"<\/code>: Bir dosya s\u00fcr\u00fcklenirken b\u00f6lgenin \u00fczerine geldi\u011finde tetiklenir. <code>event.preventDefault()<\/code> \u00e7a\u011fr\u0131s\u0131, taray\u0131c\u0131n\u0131n varsay\u0131lan s\u00fcr\u00fckle-b\u0131rak davran\u0131\u015f\u0131n\u0131 (\u00f6rne\u011fin, dosyay\u0131 yeni bir sekmede a\u00e7ma) engeller. <code>isDragOver<\/code> verisi <code>true<\/code> yap\u0131larak g\u00f6rsel bir geri bildirim sa\u011flan\u0131r.<br \/>\n*   <code>@dragleave=\"handleDragLeave\"<\/code>: Dosya b\u00f6lgeden ayr\u0131ld\u0131\u011f\u0131nda tetiklenir. <code>isDragOver<\/code> <code>false<\/code> yap\u0131larak g\u00f6rsel geri bildirim kald\u0131r\u0131l\u0131r.<br \/>\n*   <code>@drop.prevent=\"handleDrop\"<\/code>: Dosya b\u00f6lgeye b\u0131rak\u0131ld\u0131\u011f\u0131nda tetiklenir. Yine <code>event.preventDefault()<\/code> \u00e7a\u011fr\u0131s\u0131 varsay\u0131lan davran\u0131\u015f\u0131 engeller. <code>event.dataTransfer.files<\/code> objesi, b\u0131rak\u0131lan dosyalar\u0131 i\u00e7erir ve bu dosyalar <code>processFiles<\/code> metoduna g\u00f6nderilir.<\/p>\n<h4>Ebeveyn Bile\u015fenle \u0130leti\u015fim<\/h4>\n<p>\u00d6zel dosya se\u00e7icimiz, se\u00e7ilen dosyalar\u0131 veya meydana gelen olaylar\u0131 ebeveyn bile\u015fene bildirmelidir. Bu, <code>this.$emit<\/code> kullanarak \u00f6zel olaylar yayarak yap\u0131l\u0131r:<br \/>\n*   <code>@files-selected<\/code>: Dosyalar ba\u015far\u0131yla se\u00e7ildi\u011finde veya eklendi\u011finde tetiklenir. Se\u00e7ilen t\u00fcm dosyalar\u0131n listesini payload olarak g\u00f6nderir.<br \/>\n*   <code>@file-removed<\/code>: Bir dosya listeden kald\u0131r\u0131ld\u0131\u011f\u0131nda tetiklenir. Kald\u0131r\u0131lan dosyan\u0131n kendisini payload olarak g\u00f6nderir.<\/p>\n<p>Bu olaylar, ebeveyn bile\u015fenin se\u00e7ilen dosyalar\u0131 kendi <code>data<\/code>'s\u0131nda saklamas\u0131na, sunucuya y\u00fcklemesine veya ba\u015fka i\u015flemler yapmas\u0131na olanak tan\u0131r.<\/p>\n<p><strong>\u00d6rnek Ebeveyn Bile\u015fen Kullan\u0131m\u0131 (<code>App.vue<\/code>):<\/strong><\/p>\n<pre><code class=\"language-vue\"><template>\n  <div id=\"app\">\n    \n    <CustomFileSelector\n      :multiple=\"true\"\n      accept=\"image\/*,.pdf\"\n      :maxFileSize=\"2 <em> 1024 <\/em> 1024\"\n      :maxFiles=\"3\"\n      @files-selected=\"handleFilesSelected\"\n      @file-removed=\"handleFileRemoved\"\n    \/>\n    <div v-if=\"uploadedFiles.length\" class=\"uploaded-files-display\">\n      <h3>Uygulamaya Y\u00fcklenen Dosyalar:<\/h3>\n      <ul>\n        <li v-for=\"file in uploadedFiles\" :key=\"file.name\">\n          {{ file.name }} ({{ formatFileSize(file.size) }})\n        <\/li>\n      <\/ul>\n    <\/div>\n  <\/div>\n<\/template>\n\n<script>\nimport CustomFileSelector from '.\/components\/CustomFileSelector.vue';\n\nexport default {\n  name: 'App',\n  components: {\n    CustomFileSelector,\n  },\n  data() {\n    return {\n      uploadedFiles: [],\n    };\n  },\n  methods: {\n    handleFilesSelected(files) {\n      console.log('Se\u00e7ilen dosyalar:', files);\n      \/\/ Burada dosyalar\u0131 bir API'ye y\u00fckleme veya ba\u015fka bir i\u015flem yapabilirsiniz.\n      \/\/ \u015eimdilik sadece <code>uploadedFiles<\/code> array'ine ekleyelim.\n      this.uploadedFiles = files; \/\/ Ya da mevcutlara eklemek i\u00e7in: [...this.uploadedFiles, ...files]\n    },\n    handleFileRemoved(file) {\n      console.log('Kald\u0131r\u0131lan dosya:', file);\n      this.uploadedFiles = this.uploadedFiles.filter(f => f.name !== file.name || f.size !== file.size);\n    },\n    formatFileSize(bytes) {\n      if (bytes === 0) return \"0 Bytes\";\n      const k = 1024;\n      const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n      const i = Math.floor(Math.log(bytes) \/ Math.log(k));\n      return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n    },\n  },\n};\n<\/script>\n\n<style>\n#app {\n  font-family: Avenir, Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  margin-top: 60px;\n  max-width: 800px;\n  margin-left: auto;\n  margin-right: auto;\n  padding: 20px;\n  border: 1px solid #eee;\n  border-radius: 10px;\n  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);\n}\n\nh1 {\n  color: #333;\n  margin-bottom: 30px;\n}\n\n.uploaded-files-display {\n  margin-top: 30px;\n  text-align: left;\n  border-top: 1px solid #eee;\n  padding-top: 20px;\n}\n\n.uploaded-files-display h3 {\n  color: #555;\n  margin-bottom: 15px;\n}\n\n.uploaded-files-display ul {\n  list-style: disc;\n  padding-left: 20px;\n}\n\n.uploaded-files-display li {\n  margin-bottom: 8px;\n  color: #666;\n}\n<\/style><\/code><\/pre>\n<p>Bu <code>App.vue<\/code> \u00f6rne\u011fi, <code>CustomFileSelector<\/code> bile\u015fenini nas\u0131l kullanaca\u011f\u0131n\u0131z\u0131 ve onun yayd\u0131\u011f\u0131 olaylar\u0131 nas\u0131l yakalayaca\u011f\u0131n\u0131z\u0131 g\u00f6sterir. <code>multiple<\/code>, <code>accept<\/code>, <code>maxFileSize<\/code> ve <code>maxFiles<\/code> prop'lar\u0131 ile dosya se\u00e7icinin davran\u0131\u015f\u0131n\u0131 kolayca yap\u0131land\u0131rabilirsiniz.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Bu makalede, Vue.js kullanarak, taray\u0131c\u0131n\u0131n varsay\u0131lan <code>input type=\"file\"<\/code> \u00f6\u011fesinin s\u0131n\u0131rlamalar\u0131n\u0131 a\u015fan, tamamen \u00f6zelle\u015ftirilebilir ve kullan\u0131c\u0131 dostu bir dosya se\u00e7ici bile\u015feni olu\u015fturmay\u0131 ad\u0131m ad\u0131m inceledik. Vue.js'in reaktif veri y\u00f6netimi, bile\u015fen tabanl\u0131 yap\u0131s\u0131 ve olay i\u015fleme yetenekleri sayesinde, sadece g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc kontrol etmekle kalmay\u0131p ayn\u0131 zamanda geli\u015fmi\u015f \u00f6zellikler (dosya \u00f6nizlemeleri, t\u00fcr ve boyut do\u011frulamas\u0131, s\u00fcr\u00fckle-b\u0131rak deste\u011fi) ekleyebilece\u011fimizi g\u00f6rd\u00fck.<\/p>\n<p>Olu\u015fturdu\u011fumuz <code>CustomFileSelector<\/code> bile\u015feni, uygulaman\u0131z\u0131n genel tasar\u0131m\u0131yla uyumlu hale getirilebilecek esnek bir yap\u0131 sunar. <code>props<\/code> arac\u0131l\u0131\u011f\u0131yla dosya se\u00e7icinin davran\u0131\u015f\u0131n\u0131 (\u00e7oklu se\u00e7im, kabul edilen dosya t\u00fcrleri, maksimum dosya boyutu ve say\u0131s\u0131) kolayca yap\u0131land\u0131rabilir ve <code>emit<\/code> edilen olaylar sayesinde se\u00e7ilen dosyalar\u0131 ebeveyn bile\u015fenle sorunsuz bir \u015fekilde payla\u015fabilirsiniz.<\/p>\n<p>Bu bile\u015fen, temel bir ba\u015flang\u0131\u00e7 noktas\u0131d\u0131r ve ihtiya\u00e7lar\u0131n\u0131za g\u00f6re daha da geli\u015ftirilebilir. \u00d6rne\u011fin, y\u00fckleme ilerleme \u00e7ubuklar\u0131, farkl\u0131 dosya t\u00fcrleri i\u00e7in \u00f6zel ikonlar, resim d\u00fczenleme se\u00e7enekleri veya bulut depolama entegrasyonlar\u0131 gibi daha karma\u015f\u0131k \u00f6zellikler eklenebilir. Ancak, burada g\u00f6sterilen temel yap\u0131 ve Vue.js prensipleri, bu t\u00fcr geli\u015ftirmeler i\u00e7in sa\u011flam bir zemin olu\u015fturmaktad\u0131r.<\/p>\n<p>Sonu\u00e7 olarak, Vue.js ile \u00f6zel dosya se\u00e7iciler olu\u015fturmak, sadece estetik bir iyile\u015ftirme de\u011fil, ayn\u0131 zamanda kullan\u0131c\u0131 deneyimini \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131ran ve uygulaman\u0131za daha fazla kontrol sa\u011flayan g\u00fc\u00e7l\u00fc bir yakla\u015f\u0131md\u0131r. Bu makaledeki bilgiler ve \u00f6rnek kodlar, kendi projelerinizde bu t\u00fcr bile\u015fenleri ba\u015far\u0131yla uygulaman\u0131z i\u00e7in size rehberlik edecektir.<\/p>\n","protected":false},"excerpt":{"rendered":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma\nGiri\u015f: Neden \u00d6zel Bir Dosya Se\u00e7iciye \u0130htiya\u00e7 Duyar\u0131z?\nWeb uygulamalar\u0131nda kullan\u0131c\u0131lar\u0131n d","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1402],"tags":[],"class_list":{"0":"post-31285","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-vue","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma\" \/>\n<meta property=\"og:description\" content=\"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma Giri\u015f: Neden \u00d6zel Bir Dosya Se\u00e7iciye \u0130htiya\u00e7 Duyar\u0131z? Web uygulamalar\u0131nda kullan\u0131c\u0131lar\u0131n d\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-08T04:40:56+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma\",\"datePublished\":\"2025-10-08T04:40:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\"},\"wordCount\":2350,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Vue\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\",\"name\":\"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-10-08T04:40:56+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","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:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/","og_locale":"tr_TR","og_type":"article","og_title":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma","og_description":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma Giri\u015f: Neden \u00d6zel Bir Dosya Se\u00e7iciye \u0130htiya\u00e7 Duyar\u0131z? Web uygulamalar\u0131nda kullan\u0131c\u0131lar\u0131n d","og_url":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-10-08T04:40:56+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"9 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma","datePublished":"2025-10-08T04:40:56+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/"},"wordCount":2350,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Vue"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/","url":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/","name":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-10-08T04:40:56+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/vue-js-ile-basit-ozel-dosya-secici-olusturma\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Vue.js ile Basit \u00d6zel Dosya Se\u00e7ici Olu\u015fturma"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/31285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=31285"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/31285\/revisions"}],"predecessor-version":[{"id":31286,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/31285\/revisions\/31286"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=31285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=31285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=31285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}