Javascript 显示来自 twitter api 的动画 gif

Posted

技术标签:

【中文标题】Javascript 显示来自 twitter api 的动画 gif【英文标题】:Javascript displaying animated gifs from twitter api 【发布时间】:2019-08-03 00:26:44 【问题描述】:

有谁知道让 Jason Mayes Twitter Post Fetcher 包含动画 gif 的方法?我设法提取了 gif,但它们显示为 jpg 而不是 gif/video 格式...

这里还有一个codepen链接:https://codepen.io/anon/pen/bZomxM

这里是 Post Fetcher 的 javascript、CSS 和 html

/*********************************************************************
*  #### Twitter Post Fetcher v18.0.3 ####
*  Coded by Jason Mayes 2015. A present to all the developers out there.
*  www.jasonmayes.com
*  Please keep this disclaimer with my code if you use it. Thanks. :-)
*  Got feedback or questions, ask here:
*  http://www.jasonmayes.com/projects/twitterApi/
*  Github: https://github.com/jasonmayes/Twitter-Post-Fetcher
*  Updates will be posted to this site.
*********************************************************************/
(function(root, factory) 
  if (typeof define === 'function' && define.amd) 
    // AMD. Register as an anonymous module.
    define([], factory);
   else if (typeof exports === 'object') 
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory();
   else 
    // Browser globals.
    factory();
  
(this, function() 
  var domNode = '';
  var maxTweets = 20;
  var parseLinks = true;
  var queue = [];
  var inProgress = false;
  var printTime = true;
  var printUser = true;
  var formatterFunction = null;
  var supportsClassName = true;
  var showRts = true;
  var customCallbackFunction = null;
  var showInteractionLinks = true;
  var showImages = true;
  var useEmoji = true;
  var targetBlank = true;
  var lang = 'en';
  var permalinks = true;
  var dataOnly = false;
  var script = null;
  var scriptAdded = false;

  function handleTweets(tweets)
    if (customCallbackFunction === null) 
      var x = tweets.length;
      var n = 0;
      var element = document.getElementById(domNode);
      var html = '<ul>';
      while(n < x) 
        html += '<li>' + tweets[n] + '</li>';
        n++;
      
      html += '</ul>';
      element.innerHTML = html;
     else 
      customCallbackFunction(tweets);
    
  

  function strip(data) 
    return data.replace(/<b[^>]*>(.*?)<\/b>/gi, function(a,s)return s;)
        .replace(/class="(?!(tco-hidden|tco-display|tco-ellipsis))+.*?"|data-query-source=".*?"|dir=".*?"|rel=".*?"/gi,
        '');
  

  function targetLinksToNewWindow(el) 
    var links = el.getElementsByTagName('a');
    for (var i = links.length - 1; i >= 0; i--) 
      links[i].setAttribute('target', '_blank');
      links[i].setAttribute('rel', 'noopener');
    
  

  function getElementsByClassName (node, classname) 
    var a = [];
    var regex = new RegExp('(^| )' + classname + '( |$)');
    var elems = node.getElementsByTagName('*');
    for (var i = 0, j = elems.length; i < j; i++) 
        if(regex.test(elems[i].className))
          a.push(elems[i]);
        
    
    return a;
  

  function extractImagesUrl(image_data) 
    if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0) 
      var data_src = image_data.innerHTML.match(/data-image=\"([^"]+)\"/ig);
      for (var i = 0; i < data_src.length; i++) 
        data_src[i] = data_src[i].match(/data-image=\"([^"]+)\"/i)[1];
        data_src[i] = decodeURIComponent(data_src[i]) + '.jpg';
      
      return data_src;
    
  
 

  var twitterFetcher = 
    fetch: function(config) 
      if (config.maxTweets === undefined) 
        config.maxTweets = 20;
      
      if (config.enableLinks === undefined) 
        config.enableLinks = true;
      
      if (config.showUser === undefined) 
        config.showUser = true;
      
      if (config.showTime === undefined) 
        config.showTime = true;
      
      if (config.dateFunction === undefined) 
        config.dateFunction = 'default';
      
      if (config.showRetweet === undefined) 
        config.showRetweet = true;
      
      if (config.customCallback === undefined) 
        config.customCallback = null;
      
      if (config.showInteraction === undefined) 
        config.showInteraction = true;
      
      if (config.showImages === undefined) 
        config.showImages = false;
      
      if (config.useEmoji === undefined) 
        config.useEmoji = false;
      
      if (config.linksInNewWindow === undefined) 
        config.linksInNewWindow = true;
      
      if (config.showPermalinks === undefined) 
        config.showPermalinks = true;
      
      if (config.dataOnly === undefined) 
        config.dataOnly = false;
      

      if (inProgress) 
        queue.push(config);
       else 
        inProgress = true;

        domNode = config.domId;
        maxTweets = config.maxTweets;
        parseLinks = config.enableLinks;
        printUser = config.showUser;
        printTime = config.showTime;
        showRts = config.showRetweet;
        formatterFunction = config.dateFunction;
        customCallbackFunction = config.customCallback;
        showInteractionLinks = config.showInteraction;
        showImages = config.showImages;
	useEmoji = config.useEmoji;
        targetBlank = config.linksInNewWindow;
        permalinks = config.showPermalinks;
        dataOnly = config.dataOnly;

        var head = document.getElementsByTagName('head')[0];
        if (script !== null) 
          head.removeChild(script);
        
        script = document.createElement('script');
        script.type = 'text/javascript';
        if (config.list !== undefined) 
          script.src = 'https://syndication.twitter.com/timeline/list?' +
              'callback=__twttrf.callback&dnt=false&list_slug=' +
              config.list.listSlug + '&screen_name=' + config.list.screenName +
              '&suppress_response_codes=true&lang=' + (config.lang || lang) +
              '&rnd=' + Math.random();
         else if (config.profile !== undefined) 
          script.src = 'https://syndication.twitter.com/timeline/profile?' +
              'callback=__twttrf.callback&dnt=false' +
              '&screen_name=' + config.profile.screenName +
              '&suppress_response_codes=true&lang=' + (config.lang || lang) +
              '&rnd=' + Math.random();
         else if (config.likes !== undefined) 
          script.src = 'https://syndication.twitter.com/timeline/likes?' +
              'callback=__twttrf.callback&dnt=false' +
              '&screen_name=' + config.likes.screenName +
              '&suppress_response_codes=true&lang=' + (config.lang || lang) +
              '&rnd=' + Math.random();
         else 
          script.src = 'https://cdn.syndication.twimg.com/widgets/timelines/' +
              config.id + '?&lang=' + (config.lang || lang) +
              '&callback=__twttrf.callback&' +
              'suppress_response_codes=true&rnd=' + Math.random();
        
        head.appendChild(script);
      
    ,
    callback: function(data) 
      if (data === undefined || data.body === undefined) 
        inProgress = false;

        if (queue.length > 0) 
          twitterFetcher.fetch(queue[0]);
          queue.splice(0,1);
        
        return;
      

      // Remove emoji and summary card images.
      if(!useEmoji)
        data.body = data.body.replace(/(<img[^c]*class="Emoji[^>]*>)|(<img[^c]*class="u-block[^>]*>)/g, '');
      

      // Remove display images.
      if (!showImages) 
        data.body = data.body.replace(/(<img[^c]*class="NaturalImage-image[^>]*>|(<img[^c]*class="CroppedImage-image[^>]*>))/g, '');
      
      // Remove avatar images.
      if (!printUser) 
        data.body = data.body.replace(/(<img[^c]*class="Avatar"[^>]*>)/g, '');
      

      var div = document.createElement('div');
      div.innerHTML = data.body;
      if (typeof(div.getElementsByClassName) === 'undefined') 
         supportsClassName = false;
      

      function swapDataSrc(element) 
        var avatarImg = element.getElementsByTagName('img')[0];
        if (avatarImg) 
          avatarImg.src = avatarImg.getAttribute('data-src-2x');
         else 
          var screenName = element.getElementsByTagName('a')[0]
              .getAttribute('href').split('twitter.com/')[1];
          var img = document.createElement('img');
          img.setAttribute('src', 'https://twitter.com/' + screenName + 
              '/profile_image?size=bigger');
          element.prepend(img);
        
        return element;
      

      var tweets = [];
      var authors = [];
      var times = [];
      var images = [];
      var rts = [];
      var tids = [];
      var permalinksURL = [];
      var x = 0;

      if (supportsClassName) 
        var tmp = div.getElementsByClassName('timeline-Tweet');
        while (x < tmp.length) 
          if (tmp[x].getElementsByClassName('timeline-Tweet-retweetCredit').length > 0) 
            rts.push(true);
           else 
            rts.push(false);
          
          if (!rts[x] || rts[x] && showRts) 
            tweets.push(tmp[x].getElementsByClassName('timeline-Tweet-text')[0]);
            tids.push(tmp[x].getAttribute('data-tweet-id'));
            if (printUser) 
              authors.push(swapDataSrc(tmp[x].getElementsByClassName('timeline-Tweet-author')[0]));
            
            times.push(tmp[x].getElementsByClassName('dt-updated')[0]);
            permalinksURL.push(tmp[x].getElementsByClassName('timeline-Tweet-timestamp')[0]);
            if (tmp[x].getElementsByClassName('timeline-Tweet-media')[0] !==
                undefined) 
              images.push(tmp[x].getElementsByClassName('timeline-Tweet-media')[0]);
             else 
              images.push(undefined);
            
          
          x++;
        
       else 
        var tmp = getElementsByClassName(div, 'timeline-Tweet');
        while (x < tmp.length) 
          if (getElementsByClassName(tmp[x], 'timeline-Tweet-retweetCredit').length > 0) 
            rts.push(true);
           else 
            rts.push(false);
          
          if (!rts[x] || rts[x] && showRts) 
            tweets.push(getElementsByClassName(tmp[x], 'timeline-Tweet-text')[0]);
            tids.push(tmp[x].getAttribute('data-tweet-id'));
            if (printUser) 
              authors.push(swapDataSrc(getElementsByClassName(tmp[x],'timeline-Tweet-author')[0]));
            
            times.push(getElementsByClassName(tmp[x], 'dt-updated')[0]);
            permalinksURL.push(getElementsByClassName(tmp[x], 'timeline-Tweet-timestamp')[0]);
            if (getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0] !== undefined) 
              images.push(getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0]);
             else 
              images.push(undefined);
            
          
          x++;
        
      

      if (tweets.length > maxTweets) 
        tweets.splice(maxTweets, (tweets.length - maxTweets));
        authors.splice(maxTweets, (authors.length - maxTweets));
        times.splice(maxTweets, (times.length - maxTweets));
        rts.splice(maxTweets, (rts.length - maxTweets));
        images.splice(maxTweets, (images.length - maxTweets));
        permalinksURL.splice(maxTweets, (permalinksURL.length - maxTweets));
      

      var arrayTweets = [];
      var x = tweets.length;
      var n = 0;
      if (dataOnly) 
        while (n < x) 
          arrayTweets.push(
            tweet: tweets[n].innerHTML,
            author: authors[n] ? authors[n].innerHTML : 'Unknown Author',
            author_data: 
              profile_url: authors[n] ? authors[n].querySelector('[data-scribe="element:user_link"]').href : null,
              profile_image: authors[n] ? 
              'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=bigger' : null,
              profile_image_2x: authors[n] ? 'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=original' : null,
              screen_name: authors[n] ? authors[n].querySelector('[data-scribe="element:screen_name"]').title : null,
              name: authors[n] ? authors[n].querySelector('[data-scribe="element:name"]').title : null
            ,
            time: times[n].textContent,
            timestamp: times[n].getAttribute('datetime').replace('+0000', 'Z').replace(/([\+\-])(\d\d)(\d\d)/, '$1$2:$3'),
            image: (extractImagesUrl(images[n]) ? extractImagesUrl(images[n])[0] : undefined),
            images: extractImagesUrl(images[n]),
            rt: rts[n],
            tid: tids[n],
            permalinkURL: (permalinksURL[n] === undefined) ?
                '' : permalinksURL[n].href
          );
          n++;
        
       else 
        while (n < x) 
          if (typeof(formatterFunction) !== 'string') 
            var datetimeText = times[n].getAttribute('datetime');
            var newDate = new Date(times[n].getAttribute('datetime')
                .replace(/-/g,'/').replace('T', ' ').split('+')[0]);
            var dateString = formatterFunction(newDate, datetimeText);
            times[n].setAttribute('aria-label', dateString);

            if (tweets[n].textContent) 
              // IE hack.
              if (supportsClassName) 
                times[n].textContent = dateString;
               else 
                var h = document.createElement('p');
                var t = document.createTextNode(dateString);
                h.appendChild(t);
                h.setAttribute('aria-label', dateString);
                times[n] = h;
              
             else 
              times[n].textContent = dateString;
            
          
          var op = '';
          if (parseLinks) 
            if (targetBlank) 
              targetLinksToNewWindow(tweets[n]);
              if (printUser) 
                targetLinksToNewWindow(authors[n]);
              
            
            if (printUser) 
              op += '<div class="user">' + strip(authors[n].innerHTML) +
                  '</div>';
            
            op += '<p class="tweet">' + strip(tweets[n].innerHTML) + '</p>';
            if (printTime) 
              if (permalinks) 
                op += '<p class="timePosted"><a href="' + permalinksURL[n] +
                   '">' + times[n].getAttribute('aria-label') + '</a></p>';
               else 
                op += '<p class="timePosted">' +
                    times[n].getAttribute('aria-label') + '</p>';
              
            
           else 
            if (tweets[n].textContent) 
              if (printUser) 
                op += '<p class="user">' + authors[n].textContent + '</p>';
              
              op += '<p class="tweet">' +  tweets[n].textContent + '</p>';
              if (printTime) 
                op += '<p class="timePosted">' + times[n].textContent + '</p>';
              

             else 
              if (printUser) 
                op += '<p class="user">' + authors[n].textContent + '</p>';
              
              op += '<p class="tweet">' +  tweets[n].textContent + '</p>';
              if (printTime) 
                op += '<p class="timePosted">' + times[n].textContent + '</p>';
              
            
          
          if (showInteractionLinks) 
            op += '<p class="interact"><a href="https://twitter.com/intent/' +
                'tweet?in_reply_to=' + tids[n] +
                '" class="twitter_reply_icon"' +
                (targetBlank ? ' target="_blank" rel="noopener">' : '>') +
                '</a><a href="https://twitter.com/intent/retweet?' +
                'tweet_id=' + tids[n] + '" class="twitter_retweet_icon"' +
                (targetBlank ? ' target="_blank" rel="noopener">' : '>') + '</a>' +
                '<a href="https://twitter.com/intent/favorite?tweet_id=' +
                tids[n] + '" class="twitter_fav_icon"' +
                (targetBlank ? ' target="_blank" rel="noopener">' : '>') + '</a></p>';
          
          if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined) 
            var extractedImages = extractImagesUrl(images[n]);
            for (var i = 0; i < extractedImages.length; i++) 
              op += '<div class="media">' +
                    '<img src="' + extractedImages[i] +
                    '"  />' + '</div>';
            
          
          if (showImages) 
            arrayTweets.push(op);
           else if (!showImages && tweets[n].textContent.length) 
            arrayTweets.push(op);
          

          n++;
        
      

      handleTweets(arrayTweets);
      inProgress = false;

      if (queue.length > 0) 
        twitterFetcher.fetch(queue[0]);
        queue.splice(0,1);
      
    
  ;

  // It must be a global variable because it will be called by JSONP.
  window.__twttrf = twitterFetcher;
  window.twitterFetcher = twitterFetcher;
  return twitterFetcher;
));


// Prepend polyfill for IE/Edge.
(function (arr) 
  arr.forEach(function (item) 
    if (item.hasOwnProperty('prepend')) 
      return;
    
    Object.defineProperty(item, 'prepend', 
      configurable: true,
      enumerable: true,
      writable: true,
      value: function prepend() 
        var argArr = Array.prototype.slice.call(arguments),
          docFrag = document.createDocumentFragment();
        
        argArr.forEach(function (argItem) 
          var isNode = argItem instanceof Node;
          docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
        );
        
        this.insertBefore(docFrag, this.firstChild);
      
    );
  );
)([Element.prototype, Document.prototype, DocumentFragment.prototype]);

/**
 * ### HOW TO CREATE A VALID ID TO USE: ###
 * Go to www.twitter.com and sign in as normal, go to your settings page.
 * Go to "Widgets" on the left hand side.
 * Create a new widget for what you need eg "user time line" or "search" etc.
 * Feel free to check "exclude replies" if you don't want replies in results.
 * Now go back to settings page, and then go back to widgets page and
 * you should see the widget you just created. Click edit.
 * Look at the URL in your web browser, you will see a long number like this:
 * 345735908357048478
 * Use this as your ID below instead!
 */

/**
 * How to use TwitterFetcher's fetch function:
 *
 * @function fetch(object) Fetches the Twitter content according to
 *     the parameters specified in object.
 *
 * @param object Object An object containing case sensitive key-value pairs
 *     of properties below.
 *
 * You may specify at minimum the following two required properties:
 *
 * @param object.id string The ID of the Twitter widget you wish
 *     to grab data from (see above for how to generate this number).
 * @param object.domId string The ID of the DOM element you want
 *     to write results to.
 *
 * You may also specify one or more of the following optional properties
 *     if you desire:
 *
 * @param object.maxTweets [int] The maximum number of tweets you want
 *     to return. Must be a number between 1 and 20. Default value is 20.
 * @param object.enableLinks [boolean] Set false if you don't want
 *     urls and hashtags to be hyperlinked.
 * @param object.showUser [boolean] Set false if you don't want user
 *     photo / name for tweet to show.
 * @param object.showTime [boolean] Set false if you don't want time of tweet
 *     to show.
 * @param object.dateFunction [function] A function you can specify
 *     to format date/time of tweet however you like. This function takes
 *     a JavaScript date as a parameter and returns a String representation
 *     of that date.
 * @param object.showRetweet [boolean] Set false if you don't want retweets
 *     to show.
 * @param object.customCallback [function] A function you can specify
 *     to call when data are ready. It also passes data to this function
 *     to manipulate them yourself before outputting. If you specify
 *     this parameter you must output data yourself!
 * @param object.showInteraction [boolean] Set false if you don't want links
 *     for reply, retweet and favourite to show.
 * @param object.showImages [boolean] Set true if you want images from tweet
 *     to show.
 * @param object.lang [string] The abbreviation of the language you want to use
 *     for Twitter phrases like "posted on" or "time ago". Default value
 *     is "en" (English).
 */

var configProfile = 
  profile:  screenName: "toongif" ,
  domId: "example1",
  maxTweets: 5,
  enableLinks: true,
  showUser: true,
  showTime: true,
  showImages: true,
  lang: "en",
  showInteraction: true
;
twitterFetcher.fetch(configProfile);
/* 
* Example style!
* You can do whatever the hell you want on your site :-)
*/

h2 
  clear:both;


p, a 
  margin:10px 0 0 0;
  color: #FFF;
  text-decoration:none;
  font-family: 'Roboto', sans-serif;


a, a:visited 
  color: #63b7e5;
  text-decoration:none;


a:hover 
  color:#82afff;

ul 
  position: relative;
  display: inline-flex;

ul li 
  list-style:none;
  overflow:hidden;
  margin:0px 20px;
  max-width:300px;
  width: 300px;
  display:inline-block;
  text-align: left;
  vertical-align:top;
  background-color: #417abd;
  display: flex;
  flex-direction: column;


ul li:hover 
  /*background-color:#f0f3fb;*/


.user, .tweet, .timePosted 
  float:left;


.user 
  width:100%;
  color: #FFF;
  padding:10px;
  background-color:#396aa5;


.user a 
  color:#FFF;


.tweet 
  padding:20px;
  line-height: 1.65em;
  font-size:1em;
  flex: 1;


.timePosted 
  padding: 0px 20px;
  font-size: 1em;
  text-transform: uppercase;
  text-decoration: none;
 /* flex: 41;*/
  margin: 0 auto;


.user a 
 width: 100px;


.user span span 
  display:block;
  float: left;
  width: 180px


.user img, .user a > span 
  float:left;


.user div 
 /*clear: left; */
  margin: 5px 10px 0px 10px;
  float: left;
  font-size: 1em;
  width:180px


.interact 
  float:left;
  width:100%;
  margin: 20px 0px;
  text-align:center;


.interact a 
  margin: 0px 30px;
  display: inline-block;
  


.user a > span 
  margin-left:10px;


.media img 
  width:100%;
  max-width:100%;
  vertical-align: bottom;
  max-height:200px;


#linkage 
  position:fixed;
  top:0px;
  right:0px;
  background-color:#3d3d3d;
  color:#ffffff;
  text-decoration:none;
  padding:5px;
  width:10%;
  font-family:arial;


.twitter_reply_icon:before
  content:"\f075";
  display:block;
  font-family: FontAwesome;

.twitter_retweet_icon:before
  content:"\f079";
  display:block;
  font-family: FontAwesome;


.twitter_fav_icon:before
  content:"\f004";
  display:block;
  font-family: FontAwesome;
  <head><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"></head>
  <body>
    <div style="height:600px; color:#fff; padding:50px;">
    
     <div id="example1"></div>
      
    </div>
  </body>

【问题讨论】:

【参考方案1】:

问题是 Twitter 将 .gif 文件转换为 .mp4 视频格式,因此脚本应该搜索它们。我对脚本进行了一些小修改以查找这些视频。

我改变的部分:

function extractImagesUrl(image_data) 
 if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0) 
   var data_src = image_data.innerHTML.match(/data-image=\"([^"]+)\"/ig);
   var type = '';
   for (var i = 0; i < data_src.length; i++) 
    data_src[i] = data_src[i].match(/data-image=\"([^"]+)\"/i)[1];
    /* Check if source has tweet_video_thumb in data-image attribute */
    if (data_src[i].includes('tweet_video_thumb')) 
      type = 'video';
      data_src[i] = decodeURIComponent(data_src[i]).slice(-15) + '.mp4';
     else 
      type = 'image';
      data_src[i] = decodeURIComponent(data_src[i]).slice(-15) + '.jpg';
    
  
  /* return media object with type (either video or image) and id */
  var obj = 
    mediaType: type,
    id: data_src[0]
  
  return obj

与:

if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined) 
  var extractedImages = extractImagesUrl(images[n]);
  /* if mediaType === 'video' return video container else return image container */
  if (extractedImages.mediaType === 'video') 
    op += '<video autoplay loop class="media">' +
    '<source type="video/mp4" src="https://video.twimg.com/tweet_video/' + extractedImages.id + '"/>' + '</video>';
    else 
     op += '<img class="media" src="https://pbs.twimg.com/media/' + extractedImages.id + '"/>'
   

在css中:

/*.media img */
.media video 
  width:100%;
  max-width:100%;
  vertical-align: bottom;
  max-height:200px;

这是一个有效的fiddle

【讨论】:

非常感谢!快速提问 - 这也适用于视频吗?你也知道是什么使视频上方和下方的填充而不是与底部对齐吗? 好的,我设法删除了多余的填充,所以不用担心。不幸的是,您修改的代码也不适用于视频和图像,这部分是我的错,因为我之前没有指定。您能否指出如何为 jpeg、图像和视频启用它的方向?认为我需要某种 if 语句?再次感谢 @CodePine 抱歉,我有点忙,很高兴您的样式可以正常工作:) 我更新了部分代码,以便您可以同时提取图像和视频。也更新了小提琴。本来可以做得更干净一些,但至少现在可以了:) 啊!谢谢你向我展示了如何使用 else 语句。我认为视频现在正在拉动缩略图是对的吗?有什么方法可以让它在悬停时自动播放/播放还是不支持?还注意到它不会为某些视频拉大拇指 - 你知道为什么吗?你也可以向我解释一下“.slice(-15)”是做什么的吗?感谢您的出色帮助,并对我的所有问题感到抱歉! :) 没问题 :) 让它在悬停时自动播放/播放需要一些额外的修改,但绝对可行。使用.slice(),我们从初始字符串中提取视频/图像ID,在本例中为最后15 个字符。你可以阅读更多关于它here

以上是关于Javascript 显示来自 twitter api 的动画 gif的主要内容,如果未能解决你的问题,请参考以下文章

使用 Twitter 流 API,是不是可以只显示来自特定用户的推文?

仅使用 Twitter 流 API 显示来自单个用户的推文

使用 javascript 登录 Twitter?

如何检查请求是不是来自 google、facebook、twitter 和 bing 爬虫? [复制]

突出显示用户喜欢Twitter上的帖子,如Feed

Twitter Bootstrap 选项卡显示事件未在页面加载时触发