简体   繁体   中英

How to refactor a Vue instance into a working component

I have a single Vue instance that is working but now I am trying to refactor it into a component for a project I am working on. I am new to Vue so this is all learning for me.

This is a link to the code on a code pen https://codepen.io/qinglu/pen/mOKgPP?editors=1010

So far this is all I have been able to turn it into with my knowledge

export default 
{
    name: "vue-tinymce",
    data() 
    {
        return {
            content: "test content",
            content1: "text1 content1",
            tinymceOptions: tinymceOptions
        }
    },
    mounted()
    {
        var vm = this,
        options = $.extend(true, {}, tinymceOptions); // use jquery temporary

        // make an deep copy of options;should not modify tinymceOptions
        options.selector  =undefined;
        options.target  =vm.$el; // use options.target instead of options.selector

        var oldSetup = options.setup || function() {};
        options.setup = function(editor) 
        {
            console.log("setup");

            //Decorate origin one
            oldSetup(editor);  

            // Bind keyup
            editor.on("keyup",function(e)
            {
                // update model value;
                var value=editor.getContent();

                // Dom to model,this was a problem,when input in editor ? it will focus in 
                // the first line first word;
                vm.$emit("input",value); // who receive this event?
            });

            editor.on("blur",function()
            {
                vm.allowSetContent=true;
            });

            editor.on("focus",function()
            {
                vm.allowSetContent=false;
            });
        };

        tinymce.init(options)
            .then(function(editors)
            {
                vm.editor=editors[0];
            });
        }
    }
};

So there's a lot to be said here about the best way to do this, but basically you want to pass props down into your tinyMce component, then have the listener for the 'input' event you're emitting on the parent, where it can do something. I'd recommended trying Vue Single File Components for clarity and reusability.

There's even a live example of how to import and "componentize" an app from the Vue docs.

I've demonstrated this by creating a parent component in the JS called "mce-parent" that receives props and passes them through itself down into the tinyMce component. And in the 'parent-mce' component, you'll see @input which is shorthand for v-on:input that's capturing you're emit event and sending it to the scoped method doSomething() . I've modified you're example for you here https://codepen.io/anon/pen/OdmZOV?editors=1010

and here's the code:

html

<div id="example">
  <input type="text" v-model="content" class="form-control" />

  
  <div class="row">
    <div class="col-md-6">
      <!-- Don't need to pass the MCE options,
      as they're in the mce-parent component -->
      <mce-parent :value="content"></mce-parent>
    </div>
    <div class="col-md-6">
  
    </div>
  </div>
</div> 

tinyMce component

export default Vue.component("vue-tinymce",{
  template:"<textarea>{{value}}</textarea>",
  props:["value","options"],
  mounted:function(){
    var vm=this,
       options=$.extend(true, {}, tinymceOptions); // use jquery temporary
    
    // make an deep copy of options;should not modify tinymceOptions
    options.selector=undefined;
    options.target=vm.$el; // use options.target instand of options.selector
    var oldSetup=options.setup||function(){};
    
    options.setup=function(editor){
      console.log("setup");
      
      //Decorate origni one
      oldSetup(editor);
      
      // Bind keyup
      editor.on("keyup",function(e){
        // update model value;
        var value=editor.getContent();
        // Dom to model,this was a problem,when input in editor ? it will focus in the first line first word;
        vm.$emit("input",value); // who recieve this event?
      });
      
      editor.on("blur",function(){
        vm.allowSetContent=true;
      });
      
      editor.on("focus",function(){
         vm.allowSetContent=false;
      })
    };
    
    tinymce.init(options).then(function(editors){
      vm.editor=editors[0];
    })
  },
  watch:{
    value:function(content)
    {
      if(this.editor&&this.allowSetContent)
      {
        // setContent will let editor focus in first line and first world
        this.editor.setContent(content);
      }
    }
  }
});

mce-parent component

// this is just an example
import tinyMce from './components/TinyMce.js';
Vue.component("mce-parent",{
  data : {
    return {
      tinymceOptions : tinymceOptions,
    }
  },
  template:`<div class='mce-parent'>`
              `<tiny-mce @input="doSomething" :value="value" :options="tinymceOptions"/>`
              `</tiny-mce>`
            `</div>`,
  props : ['value'],
  components : { 'tiny-mce' : tinyMce },
  methods : {
    doSomething(value){
      console.log(value)
    }
  }
});

var tinymceOptions={
  selector: 'textarea',
  height: 200,
  menubar: true,
  plugins: [
    'advlist autolink lists link image charmap print preview hr anchor pagebreak',
    'searchreplace wordcount visualblocks visualchars code fullscreen',
    'insertdatetime media nonbreaking save table contextmenu directionality',
    'emoticons template paste textcolor colorpicker textpattern imagetools codesample toc'
  ],
  toolbar1: 'undo redo | insert | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
  toolbar2: 'print preview media | forecolor backcolor emoticons | codesample',
  valid_elements:"*[*]",
  content_css: '//www.tinymce.com/css/codepen.min.css',
  images_upload_url: 'postAcceptor.php',
  images_upload_base_path: '/some/basepath',
  images_upload_credentials: true,
  images_upload_handler: function (blobInfo, success, failure) {
    var xhr, formData;
    xhr = new XMLHttpRequest();
    xhr.withCredentials = false;
    xhr.open('POST', 'postAcceptor.php');
    xhr.onload = function() {
      var json;

      if (xhr.status != 200) {
        failure('HTTP Error: ' + xhr.status);
        return;
      }
      json = JSON.parse(xhr.responseText);

      if (!json || typeof json.location != 'string') {
        failure('Invalid JSON: ' + xhr.responseText);
        return;
      }
      success(json.location);
    };
    formData = new FormData();
    formData.append('file', blobInfo.blob(), fileName(blobInfo));
    xhr.send(formData);
  },
  image_title: true, 
  // enable automatic uploads of images represented by blob or data URIs
  automatic_uploads: true,
  // URL of our upload handler (for more details check: https://www.tinymce.com/docs/configure/file-image-upload/#images_upload_url)
  images_upload_url: 'postAcceptor.php',
  // here we add custom filepicker only to Image dialog
  file_picker_types: 'image', 
  // and here's our custom image picker
  file_picker_callback: function(cb, value, meta) {
    var input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    
    // Note: In modern browsers input[type="file"] is functional without 
    // even adding it to the DOM, but that might not be the case in some older
    // or quirky browsers like IE, so you might want to add it to the DOM
    // just in case, and visually hide it. And do not forget do remove it
    // once you do not need it anymore.

    input.onchange = function() {
      var file = this.files[0];
      
      // Note: Now we need to register the blob in TinyMCEs image blob
      // registry. In the next release this part hopefully won't be
      // necessary, as we are looking to handle it internally.
      var id = 'blobid' + (new Date()).getTime();
      var blobCache = tinymce.activeEditor.editorUpload.blobCache;
      var blobInfo = blobCache.create(id, file);
      blobCache.add(blobInfo);
      
      // call the callback and populate the Title field with the file name
      cb(blobInfo.blobUri(), { title: file.name });
    };
    
    input.click();
  }
};

main Vue app entry point


var vm=new Vue({
  el:"#example",
  data:{
    content:"test content",
    content1:"text1 content1"
   }
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM