Electron: рдореИрдВ <a>рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдУрдПрд╕ рдмреНрд░рд╛рдЙрдЬрд╝рд░</a> рд╕реЗ рдпреВрдЖрд░рдПрд▓ рдХреИрд╕реЗ рдЦреЛрд▓реВрдВ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 1 рдЕрдкреНрд░реИрд▓ 2015  ┬╖  26рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: electron/electron

рдореИрдВ рдПрдХ рдмрд╛рд╣рд░реА рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рд▓реЗ рдЬрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдореИрдВ рдЙрд╕реЗ рдХреИрд╕реЗ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдБ?

рдзрдиреНрдпрд╡рд╛рдж!

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдореБрдЭреЗ рдпрд╣ рдХреЛрдб рд╕реНрдирд┐рдкреЗрдЯ SO рдкрд░ рдорд┐рд▓рд╛:

    var shell = require('electron').shell;
    //open links externally by default
    $(document).on('click', 'a[href^="http"]', function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

рдЗрд╕реЗ рдореЗрд░реА рдореБрдЦреНрдп рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЫреЛрдбрд╝ рджрд┐рдпрд╛, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдореИрдВ рдХрд╣ рд╕рдХрддрд╛ рд╣реВрдВ, рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреЗрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рд▓рд┐рдВрдХ рдХреЗ рд▓рд┐рдП рднреА рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдореИрдВ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдкрд░ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реВрдВ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕рдореЗрдВ рдХреЛрдИ рдХрдорд┐рдпрд╛рдВ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдореБрдЭреЗ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╡рд┐рдЪрд╛рд░?

рд╕рднреА 26 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

@luicaps рдбреЙрдХреНрд╕ рдпрд╣рд╛рдБ рд╣реИрдВ https://github.com/atom/atom-shell/blob/master/docs/api/shell.md#shellopenexternalurl

рдЕрдкрдиреЗ рд╕реЗрдЯрдЕрдк рдкрд░, рдореИрдВрдиреЗ shell.openExternal('http://example.com') рдФрд░ shell.openItem('http://example.com') рджреЛрдиреЛрдВ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рджреЛрдиреЛрдВ рдиреЗ рдкреГрд╖реНрдарднреВрдорд┐ рдореЗрдВ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдЦреЛрд▓реАред

рдореИрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ child_process.execSync('start http://example.com') Win32 рдкрд░ рдФрд░ child_process.execSync('open http://example.com') рддреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкреЙрдк рдЕрдк рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдзреНрдпрд╛рди рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдбрд╛рд░реНрд╡рд┐рди рдкрд░ред

рд▓рд┐рдирдХреНрд╕ рдкрд░, рдЖрдк xdg-open рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
child_process.execSync('xdg-open http://example.com')

рдореИрдВрдиреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдиреЛрдб-рдУрдкрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рднрд╛рдЧрдиреЗ рдФрд░ рдЗрд╕ рддрд░рд╣ рдХреЗ рд╕рд╛рде рдЦрд┐рд▓рд╡рд╛рдбрд╝ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ рдЗрд╕реЗ рдЖрдЬрд╝рдорд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рджреЛрд╕реНрддреЛрдВ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдмрд╣реБрдд рдЕрдЪреНрдЫреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рд╕реЛрдЪ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ " http://someurl.com " рдЬреИрд╕реЗ рдпреВрдЖрд░рдПрд▓ рдХреЛ рдЦреЛрд▓рдиреЗ рдХреЗ рдкреНрд░рдпрд╛рд╕ рдХреЛ рдХреИрд╕реЗ рд░реЛрдХрд╛ рдЬрд╛рдП рдФрд░ рдлрд┐рд░ shell.openExternal рд╕рд╛рде рдЦреЛрд▓рд╛ рдЬрд╛рдП? рд╕реЗрд╡рд╛ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЗрд╡рд▓ рдЙрд╕реА рдбреЛрдореЗрди рдкрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдХреНрдпрд╛ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИ? /cc @maxogden @AlicanC

рдпрд╣рд╛рдБ @havenchyk рдЬреИрд╕рд╛ рд╣реА рдкреНрд░рд╢реНрди рд╣реИ, рдХреНрдпрд╛ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдмрд╛рд╣рд░реА рд▓рд┐рдВрдХ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ?

рдпрджрд┐ рдЖрдкрдХрд╛ рдРрдк рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рдВрдбреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЖрдк рдЧрд╛рд░рдВрдЯреА рджреЗ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЖрдкрдХреЗ рдРрдк рдХрд╛ рдкреНрд░рддреНрдпреЗрдХ рдмрд╛рд╣рд░реА рд▓рд┐рдВрдХ рдПрдХ рдирдИ рд╡рд┐рдВрдбреЛ рдореЗрдВ рдЦреБрд▓рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП target="_blank" ), рддреЛ рдЖрдк рдХреБрдЫ рдРрд╕рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

webContents.on('new-window', function(event, url){
  event.preventDefault();
  open(url);
});

рдЬрд╣рд╛рдВ webContents рдЖрдкрдХрд╛ рдореБрдЦреНрдп рдмреНрд░рд╛рдЙрдЬрд╝рд░рд╡рд┐рдВрдбреЛ рдХреА рд╡реЗрдм рд╕рд╛рдордЧреНрд░реА рд╣реИ рдФрд░ open рдПрдХ рдРрд╕рд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдЖрдкрдХреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ url рдЦреЛрд▓рддрд╛ рд╣реИ (рдореИрдВ AlicanC рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрд╢рдВрд╕рд┐рдд рдиреЛрдб-рдУрдкрди рдХрд╛ рдЙрдкрдпреЛрдЧ

рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ _any_ рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рд╣реЛрдиреЗ рдкрд░ рдХреЛрдИ рдИрд╡реЗрдВрдЯ рдирд┐рдХрд╛рд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП рдРрдк рддрдп рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЦреЛрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдпрд╣ рдореМрдЬреВрдж рд╣реИ рддреЛ рдореБрдЭреЗ рдРрд╕реА рдХреЛрдИ рдШрдЯрдирд╛ рдирд╣реАрдВ рдорд┐рд▓реА рд╣реИред

рдореБрдЭреЗ рдпрд╣ рдХреЛрдб рд╕реНрдирд┐рдкреЗрдЯ SO рдкрд░ рдорд┐рд▓рд╛:

    var shell = require('electron').shell;
    //open links externally by default
    $(document).on('click', 'a[href^="http"]', function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

рдЗрд╕реЗ рдореЗрд░реА рдореБрдЦреНрдп рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЫреЛрдбрд╝ рджрд┐рдпрд╛, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдореИрдВ рдХрд╣ рд╕рдХрддрд╛ рд╣реВрдВ, рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреЗрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рд▓рд┐рдВрдХ рдХреЗ рд▓рд┐рдП рднреА рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдореИрдВ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдкрд░ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реВрдВ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕рдореЗрдВ рдХреЛрдИ рдХрдорд┐рдпрд╛рдВ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдореБрдЭреЗ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╡рд┐рдЪрд╛рд░?

рдореИрдВ рдХреЛрдб рдХреЗ рдЗрд╕ рдЯреБрдХрдбрд╝реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдБ:

var handleRedirect = (e, url) => {
  if(url != webContents.getURL()) {
    e.preventDefault()
    require('electron').shell.openExternal(url)
  }
}

webContents.on('will-navigate', handleRedirect)
webContents.on('new-window', handleRedirect)

рдкрд╣рд▓реЗ рд╕реНрдкреЙрди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдШреЛрд╖рд┐рдд рдХрд░реЗрдВ

`app.controller('GuideCtrl', ['$scope', ($scope)=>{
рдХреЙрдиреНрд╕реНрдЯ рд╕реНрдкреЙрди = рдЖрд╡рд╢реНрдпрдХрддрд╛ ('рдЪрд╛рдЗрд▓реНрдб_рдкреНрд░реЛрд╕реЗрд╕')ред рд╕реНрдкреЙрди;

  $scope.openBrowser=(url)=>{
     let exec = spawn('explore', [url], {});
     exec.stdout.on('data', (data)=> {
        console.log('stdout: ' + data)
     });
  }

}])`

рдФрд░ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ

<a ng-click="openBrowser('https://google.com')">Goto google</a>

рдХреНрдпрд╛ shell.openExternal рдореЗрдВ рдХреЛрдИ рд╕реБрд░рдХреНрд╖рд╛ рд╕рдорд╕реНрдпрд╛ рд╣реИ? рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдпрджрд┐ рд▓рд┐рдВрдХ рдиреЗрдЯ рд╕реЗ рдмрд╛рд╣рд░ рдЖрддреЗ рд╣реИрдВ рддреЛ рд░реЙ рдиреЗрдЯ рдбреЗрдЯрд╛ shell.openExternal рдпрд╛ рдЙрдкрд░реЛрдХреНрдд рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред рдХреНрдпрд╛ shell.openExternal рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреБрдЫ рднреА рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реЛрдиреЗ рд╡рд╛рд▓рд╛ рд╣реИ? рдХреНрдпрд╛ рдореБрдЭреЗ рд╕реНрдХреАрдорд╛ рдХреЗ рд▓рд┐рдП рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ?

@rubencodes рд╕реЗ рдХреЛрдб рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдореИрдВрдиреЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛:

const shell = require('electron').shell; $('.open-in-browser').click((event) => { event.preventDefault(); shell.openExternal(event.target.href); });

рдлрд┐рд░ рдЖрдкрдХреЛ рдмрд╕ 'рдУрдкрди-рдЗрди-рдмреНрд░рд╛рдЙрдЬрд╝рд░' рд╡рд░реНрдЧ рдХреЛ рд╣рд░ рдЙрд╕ рддрддреНрд╡ рдХреЗ рд▓рд┐рдП рдЫреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рд╕реЗ рдЖрдк рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЦреЛрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред

рдпрд╣рд╛рдВ рдПрдХ рд╣реИ рдЬрд┐рд╕реЗ jQuery рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЕрдЧрд░ рдХреЛрдИ рдФрд░ рдЗрд╕рдХрд╛ рд╢рд┐рдХрд╛рд░ рдХрд░ рд░рд╣рд╛ рд╣реИред рдпрд╣ рдмрд╛рд╣рд░реА рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ 'http' рд╕реЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдХрд┐рд╕реА рднреА рд▓рд┐рдВрдХ рдХреЛ рдЕрдкрдиреЗ рдЖрдк рдЦреЛрд▓ рджреЗрдЧрд╛ред

рдЗрд╕реЗ рдЕрдкрдиреА рд░реЗрдВрдбрд░рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд░рдЦреЗрдВ:

// Open all links in external browser
let shell = require('electron').shell
document.addEventListener('click', function (event) {
  if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
    event.preventDefault()
    shell.openExternal(event.target.href)
  }
})

рдпрджрд┐ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╕рднреА <a> рдЯреИрдЧ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЦреБрд▓реЗ, рддреЛ рдЗрд╕реЗ рдЕрдкрдиреЗ main.ts рдореЗрдВ рдЖрдЬрд╝рдорд╛рдПрдБ:

const shell = require('electron').shell;

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault()
  shell.openExternal(url)
});

рдпрд╣ рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдореЗрд░реЗ рдЬреИрд╕рд╛ рдПрдХ рдкреЗрдЬ рдРрдк рд╣реИред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдЖрдкрдХреЛ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рд╕рдлрд╛рдИ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред

рдореИрдВ рдХреЗрд╡рд▓ рдпрд╣ рджреЛрд╣рд░рд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рд╢реНрд╡реЗрддрд╕реВрдЪреА рдХреЗ рдмрд┐рдирд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╢рд╛рдпрдж рдПрдХ рдЕрдВрддрд░ рд╕реБрд░рдХреНрд╖рд╛ рдЫреЗрдж рд╣реИред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рд╕рднреА рд╡рд┐рднрд┐рдиреНрди рдпреЛрдЬрдирд╛рдПрдВ рдХреНрдпрд╛ рдХрд░рддреА рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рдЗрдирдкреБрдЯ рдХреНрдпрд╛ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреА рдПрдХ рд▓рд┐рдВрдХ

 <a href="imessage:hello">click me</a>

рдореИрдХреЛрдЬрд╝ рдкрд░ рдХреНрд░реЛрдо рдФрд░ рд╕рдлрд╛рд░реА рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕рдВрдХреЗрдд рджреЗрдЧрд╛ рд▓реЗрдХрд┐рди рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдХреЗ рдКрдкрд░ рдХреЛрдб рдХреЗ рд╕рд╛рде рдРрдк рдЦреБрд▓ рдЬрд╛рдПрдЧрд╛ред

рдРрд╕рд╛ рд▓рдЧрднрдЧ рдорд╣рд╕реВрд╕ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рд╕реНрд╡рдпрдВ рдХреЛ рдпрд╣рд╛рдВ рдЕрдзрд┐рдХ рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрдЬрд╛рдп рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЛ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЫреЛрдбрд╝ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЗрд╕реЗ рдЕрдкрдиреЗ рджрдо рдкрд░ рдХреИрд╕реЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдмрдирд╛рдпрд╛ рдЬрд╛рдПред

рдХрдо рд╕реЗ рдХрдо рдЖрдк рд╢рд╛рдпрдж рдХреБрдЫ рдРрд╕рд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ

function isSafeishURL(url) {
  return url.startsWith('http:') || url.startsWith('https:');
}

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault();
  if (isSafeishURL(url)) {
    shell.openExternal(url);
  }
});

@greggman https://electronjs.org/docs/api/session#sessetpermissionrequesthandlerhandler рдореЗрдВ рдЦреБрд▓реЗ рдмрд╛рд╣рд░реА рдЕрдиреБрдорддрд┐ рдкреНрд░рдХрд╛рд░

рдЖрдк рдЙрдиреНрд╣реЗрдВ рдмреНрд▓реЙрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

рдирдорд╕реНрддреЗ, рдореИрдВ vue.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдЙрдкрд░реЛрдХреНрдд рдЪрд░реНрдЪрд╛ рд╕реЗ рдкреНрд░реЗрд░рд┐рдд рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реВрдВ, рдЕрдЧрд░ рдореЗрд░реЗ рдЬреИрд╕реЗ рдХрд┐рд╕реА рд╡реНрдпрдХреНрддрд┐ рдХреЛ vue рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ, рддреЛ рдореИрдВ рдЕрдкрдирд╛ рдХреЛрдб рдпрд╣рд╛рдВ рдкреЗрд╕реНрдЯ рдХрд░рддрд╛ рд╣реВрдВред

<template>
<div class="board-item" v-for="element in list" :key="element.id">
<span><a class='board-item-a' :href='element.url' target='_blank'>{{element.title}}</a></span>
</div>
</template>

<script>
mounted () {
this.$el.querySelectorAll('.board-item-a').forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault()
require('electron').shell.openExternal(e.target.href)
})
})
},
</script>

@alangranger - ts рд╕рдВрд╕реНрдХрд░рдг рдХреА рдЯрд┐рдкреНрдкрдгреА рдХреЗ рдЖрдзрд╛рд░ рдкрд░:

const {app, shell, BrowserWindow} = require('electron');

...
mainWindow.webContents.on('new-window', function(event, url){
   event.preventDefault();
   shell.openExternal(url);
});

рдбреЗрдЯрд╛ рдпреВрдЖрд░рдПрд▓ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛?

рдХреЛрдгреАрдп 7 рд╕рдВрд╕реНрдХрд░рдг (рд▓рд╛рдЗрд╡ рд░реАрд▓реЛрдб рдХреЗ рд╕рд╛рде):

        const openExternalLinksInOSBrowser = (event, url) => {
            if (url.match(/.*localhost.*/gi) === null && (url.startsWith('http:') || url.startsWith('https:'))) {
                event.preventDefault();
                shell.openExternal(url);
            }
        };
        win.webContents.on('new-window', openExternalLinksInOSBrowser);
        win.webContents.on('will-navigate', openExternalLinksInOSBrowser);

url.match(/.*localhost.*/gi) === null рднрд╛рдЧ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЕрдиреНрдпрдерд╛ рдЬрдм рдЖрдк рдЕрдкрдиреЗ рдХреЛрдгреАрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдХреБрдЫ рдмрджрд▓рддреЗ рд╣реИрдВ рддреЛ рдпрд╣ рдЖрдкрдХреЗ OS рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдРрдк рдореЗрдВ рдЗрд╕реЗ рдкреБрдирдГ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдирдИ рд╡рд┐рдВрдбреЛ/рдЯреИрдм рдЦреЛрд▓реЗрдЧрд╛ред

рд╕рднреА рд╡рд┐рдзрд┐рдпрд╛рдВ рдареАрдХ рдХрд╛рдо рдХрд░рддреА рд╣реИрдВ рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдЧреИрд░ рд░реВрдЯ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рдРрдк рдкрд░, рдореИрдВ рд░реВрдЯ рдПрд▓рд┐рд╡реЗрдЯреЗрдб рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдУрдПрд╕ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдкрд░ рдмрд╛рд╣рд░реА рдпреВрдЖрд░рдПрд▓ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ?

рдмрд╕ рдЕрдиреНрдп Vue.js рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрддрд░ рдкреЛрд╕реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред

<template>
  <div>
    <a href="https://google.com" target="_blank" @click.prevent="openExternalBrowser">Google.com Status</a>
  </div>
</template>

<script>
const { remote } = require('electron');

export default {
  name: 'HelloWorld',
  methods: {
    openExternalBrowser(e) {
      remote.shell.openExternal(e.target.href);
    },
  },
};
</script>

рдмрд╕ рдЕрдиреНрдп Vue.js рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрддрд░ рдкреЛрд╕реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред

<template>
  <div>
    <a href="https://google.com" target="_blank" @click.prevent="openExternalBrowser">Google.com Status</a>
  </div>
</template>

<script>
const { remote } = require('electron');

export default {
  name: 'HelloWorld',
  methods: {
    openExternalBrowser(e) {
      remote.shell.openExternal(e.target.href);
    },
  },
};
</script>

рд╢реБрдХреНрд░рд┐рдпрд╛ред

main.js :

app.on('web-contents-created', (e, contents) => {
    contents.on('new-window', (e, url) => {
      e.preventDefault();
      require('open')(url);
    });
    contents.on('will-navigate', (e, url) => {
      if (url !== contents.getURL()) e.preventDefault(), require('open')(url);
    });
});

рдЖрдкрдХреЛ рдЦреБрд▓рд╛ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

npm i open --save

рдмрд╕ рдЕрдиреНрдп Vue.js рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрддрд░ рдкреЛрд╕реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред

@ travis5491811 рдпрд╣ рджрд╛рд╣рд┐рдиреЗ рдкреГрд╖реНрда рдХреЗ рд╕рд╛рде рдПрдХ рдФрд░ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рд╡рд┐рдВрдбреЛ рдЦреЛрд▓рддрд╛ рд╣реИред рдХреНрдпрд╛ рдпрд╣ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИ?

рдирд╣реАрдВ, рдЬрдм рдареАрдХ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдореЗрд░реА рдкреЛрд╕реНрдЯ рдХреЛ рдереНрд░реЗрдб рдЯрд┐рдХрдЯ "рдореИрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдУрдПрд╕ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕реЗ рдпреВрдЖрд░рдПрд▓ рдХреИрд╕реЗ рдЦреЛрд▓реВрдВ" рдХрд╛ рдЬрд╡рд╛рдм рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЙрддреНрддрд░ рдореЗрд░реЗ рдРрдк рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди v5.0.11 , Vue v2.6.10 , рдХрдИ рд╡рд┐рдВрдбреЛрдЬ 10 рдФрд░ рд▓рд┐рдирдХреНрд╕ рдбреЗрд╕реНрдХрдЯреЙрдк рдорд╢реАрдиреЛрдВ рдкрд░ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛

рдмрд╕ рдЕрдиреНрдп Vue.js рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрддреНрддрд░ рдкреЛрд╕реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред

@ travis5491811 рдпрд╣ рджрд╛рд╣рд┐рдиреЗ рдкреГрд╖реНрда рдХреЗ рд╕рд╛рде рдПрдХ рдФрд░ рдЗрд▓реЗрдХреНрдЯреНрд░реЙрди рд╡рд┐рдВрдбреЛ рдЦреЛрд▓рддрд╛ рд╣реИред рдХреНрдпрд╛ рдпрд╣ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИ?

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

DanielDignam picture DanielDignam  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

etiktin picture etiktin  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

feross picture feross  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

tenry92 picture tenry92  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

lealife picture lealife  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ