如何将 codepen 作为 HTML 嵌入 vue.js

How to embed codepen as HTML in vue.js

我不知道如何使用推荐的 HTML 方法在 Vue 应用程序中嵌入代码笔。 由于 <script> 标签不能成为 Vue 组件模板的一部分,我尝试将其添加到 index.html 中,但我的 Vue 应用程序被注入其中,但没有成功。但是,当我尝试将 html 代码粘贴到 Vue 所在的 div 之外时,该代码按应有的方式变成了 iFrame。

这里是 HTML 嵌入:

<p data-height="265" data-theme-id="0" data-slug-hash="JyxKMg" data-default-tab="js,result" data-user="sindael" data-embed-version="2" data-pen-title="Fullscreen image gallery using Wallop, Greensock and Flexbox" class="codepen">See the Pen <a href="https://codepen.io/sindael/pen/JyxKMg/">Fullscreen image gallery using Wallop, Greensock and Flexbox</a> by Dan (<a href="https://codepen.io/sindael">@sindael</a>) on <a href="https://codepen.io">CodePen</a>.</p>

和脚本:

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

直接嵌入 iFrame 可以正常工作,但我想知道。有没有办法让 html 工作?

查看https://static.codepen.io/assets/embed/ei.js,然后你会看到它执行两个步骤:

  1. 检查document.getElementsByClassName是否存在,如果不存在则创建。

  2. 一个 IIFE 执行嵌入。

下面是一个简单的演示方式:

  1. https://static.codepen.io/assets/embed/ei.js

  2. 复制源代码
  3. 复制第一步的代码然后将其包装为一个函数= _codepen_selector_contructor

  4. 复制第二步的代码,去掉末尾的(),然后包装成一个函数=_codepen_embed_method

  5. 创建一个vue-directive(我更喜欢使用指令支持直接处理Dom元素的功能,你可以使用其他解决方案),然后执行_codepen_selector_contructor_codepen_embed_method

  6. 可能您想将_codepen_embed_method中的document替换为el,然后执行_codepen_embed_method(el)。这样就不会影响其他元素了。

下面的demo使用了hook='inserted',如果inserted不能满足您的要求,您可以使用其他hook

let vCodePen = {}

vCodePen.install = function install (Vue) {//copy from https://static.codepen.io/assets/embed/ei.js
  let _codepen_selector_contructor = function () {
    document.getElementsByClassName||(document.getElementsByClassName=function(e){var n,t,r,a=document,o=[];if(a.querySelectorAll)return a.querySelectorAll("."+e);if(a.evaluate)for(t=".//*[contains(concat(' ', @class, ' '), ' "+e+" ')]",n=a.evaluate(t,a,null,0,null);r=n.iterateNext();)o.push(r);else for(n=a.getElementsByTagName("*"),t=new RegExp("(^|\s)"+e+"(\s|$)"),r=0;r<n.length;r++)t.test(n[r].className)&&o.push(n[r]);return o})
  }
  let _codepen_embed_method = //copy from https://static.codepen.io/assets/embed/ei.js then removed `()` from the end
    function(){function e(){function e(){for(var e=document.getElementsByClassName("codepen"),t=e.length-1;t>-1;t--){var u=a(e[t]);if(0!==Object.keys(u).length&&(u=o(u),u.user=n(u,e[t]),r(u))){var c=i(u),l=s(u,c);f(e[t],l)}}m()}function n(e,n){if("string"==typeof e.user)return e.user;for(var t=0,r=n.children.length;t<r;t++){var a=n.children[t],o=a.href||"",i=o.match(/codepen\.(io|dev)\/(\w+)\/pen\//i);if(i)return i[2]}return"anon"}function r(e){return e["slug-hash"]}function a(e){for(var n={},t=e.attributes,r=0,a=t.length;r<a;r++){var o=t[r].name;0===o.indexOf("data-")&&(n[o.replace("data-","")]=t[r].value)}return n}function o(e){return e.href&&(e["slug-hash"]=e.href),e.type&&(e["default-tab"]=e.type),e.safe&&("true"===e.safe?e.animations="run":e.animations="stop-after-5"),e}function i(e){var n=u(e),t=e.user?e.user:"anon",r="?"+l(e),a=e.preview&&"true"===e.preview?"embed/preview":"embed",o=[n,t,a,e["slug-hash"]+r].join("/");return o.replace(/\/\//g,"//")}function u(e){return e.host?c(e.host):"file:"===document.location.protocol?"https://codepen.io":"//codepen.io"}function c(e){return e.match(/^\/\//)||!e.match(/https?:/)?document.location.protocol+"//"+e:e}function l(e){var n="";for(var t in e)""!==n&&(n+="&"),n+=t+"="+encodeURIComponent(e[t]);return n}function s(e,n){var r;e["pen-title"]?r=e["pen-title"]:(r="CodePen Embed "+t,t++);var a={id:"cp_embed_"+e["slug-hash"].replace("/","_"),src:n,scrolling:"no",frameborder:"0",height:d(e),allowTransparency:"true",allowfullscreen:"true",allowpaymentrequest:"true",name:"CodePen Embed",title:r,"class":"cp_embed_iframe "+(e["class"]?e["class"]:""),style:"width: "+p+"; overflow: hidden;"},o="<iframe ";for(var i in a)o+=i+'="'+a[i]+'" ';return o+="></iframe>"}function d(e){return e.height?e.height:300}function f(e,n){if(e.parentNode){var t=document.createElement("div");t.className="cp_embed_wrapper",t.innerHTML=n,e.parentNode.replaceChild(t,e)}else e.innerHTML=n}function m(){"function"==typeof __CodePenIFrameAddedToPage&&__CodePenIFrameAddedToPage()}var p="100%";e()}function n(e){/in/.test(document.readyState)?setTimeout("window.__cp_domReady("+e+")",9):e()}var t=1;window.__cp_domReady=n,window.__CPEmbed=e,n(function(){new __CPEmbed})}

  let defaultProps = {class: 'codepen', 'data-height':265, 'data-theme-id':0, 'data-slug-hash':'', 'data-default-tab':'js,result', 'data-user':'sindael', 'data-embed-version':'2', 'data-pen-title':''}
  Vue.directive('code-pen', {
    inserted: function (el, binding, vnode) {
      let options = Object.assign({}, defaultProps, binding.value)
      Object.entries(options).forEach((item) => {
        el.setAttribute(item[0], item[1])
      })
      setTimeout(() => {
        _codepen_selector_contructor()
        _codepen_embed_method() //_codepen_embed_method(el); you can pass el to take place of `document`
      }, 100)
    },
    componentUpdated: function (el, binding, vnode) {
    }
  })
}

Vue.use(vCodePen)
Vue.config.productionTip = false
app = new Vue({
  el: "#app",
  data: {
    keyword: '',
  },
  mounted: function () {
  },
  methods: {
  }
})
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>

<div id="app">
<p v-code-pen="{class: 'codepen', 'data-height':'265', 'data-theme-id':0, 'data-slug-hash':'JyxKMg', 'data-default-tab':'js,result', 'data-user':'sindael', 'data-embed-version':'2', 'data-pen-title':'Test'}">
  <a href="https://codepen.io/sindael/pen/JyxKMg/"></a>
</p>
</div>